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

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

AI Voice Designer: Custom Voice Generation Workflow

This document outlines the detailed design specifications, wireframe descriptions, color palette recommendations, and user experience (UX) guidelines for the "AI Voice Designer" tool. The goal is to provide a comprehensive, intuitive, and powerful interface for users to create completely custom AI voices.


1. Detailed Design Specifications: Voice Characteristics

The AI Voice Designer will allow users to manipulate a wide array of parameters to sculpt their desired voice. These parameters are categorized for clarity and ease of use.

1.1 Core Voice Attributes

  • Gender:

* Options: Male, Female, Androgynous/Neutral.

* Control: Radio buttons or a slider from "Female" to "Male" with "Neutral" in the center.

  • Age:

* Options: Child, Teen, Young Adult, Adult, Middle-Aged, Senior.

* Control: Slider or dropdown menu.

  • Accent/Language:

* Primary Accent: Dropdown with common accents (e.g., American Standard, British RP, Australian, Indian, Spanish, French, German).

* Secondary Accent (Optional): A less dominant accent influence.

* Control: Searchable dropdowns with multi-select capability for nuanced accents.

1.2 Delivery Style & Tone

  • Emotion/Tone:

* Options: Calm, Energetic, Authoritative, Friendly, Playful, Serious, Soothing, Expressive, Monotone, Excited, Sad, Angry, Fearful.

* Control: Multiple sliders (e.g., "Calm <-> Energetic," "Serious <-> Playful") or a selection of predefined emotional presets with intensity sliders.

  • Pitch:

* Range: Low, Medium, High.

* Control: Slider.

  • Pace/Speed:

* Range: Slow, Medium, Fast.

* Control: Slider (words per minute approximation).

  • Volume/Loudness:

* Range: Soft, Normal, Loud.

* Control: Slider.

  • Speech Style:

* Options: Conversational, Narrator, Announcer, Robotic, Whisper, Singing (basic melodic contour).

* Control: Dropdown or radio buttons.

1.3 Fine-Tuning & Nuance

  • Resonance/Depth:

* Range: Shallow, Normal, Deep.

* Control: Slider.

  • Clarity/Articulation:

* Range: Muffled, Normal, Crisp.

* Control: Slider.

  • Breathiness:

* Range: None, Slight, Noticeable.

* Control: Slider.

  • Vocal Texture:

* Options: Smooth, Husky, Raspy, Clear, Warm, Cold.

* Control: Dropdown or multiple checkboxes.

  • Pause Duration:

* Range: Short, Normal, Long.

* Control: Slider (for overall pause tendency).

  • Intonation Variety:

* Range: Monotonous, Normal, Expressive.

* Control: Slider.

1.4 Voice Identity & Management

  • Voice Name: Text input field (e.g., "PantheraHive Assistant," "Narrator Alpha").
  • Voice Description: Multi-line text area for notes on the voice's intended use or specific characteristics.
  • Voice ID: Automatically generated unique identifier upon saving.

2. Wireframe Descriptions

The user interface will be designed for clarity, efficiency, and real-time feedback, employing a two-column layout for optimal interaction.

2.1 Main Layout Structure

  • Left Panel (Control Panel - ~35-40% width): Dedicated to voice characteristic adjustments.
  • Right Panel (Preview & Actions - ~60-65% width): Features text input for preview, audio playback, and voice management actions.

2.2 Left Panel: Voice Attribute Controls

  • Header: "Design Your Voice"
  • Sections (Collapsible/Expandable):

* "Core Identity":

* Gender (Radio buttons/Slider)

* Age (Slider/Dropdown)

* Accent/Language (Searchable Dropdowns for Primary/Secondary)

* "Delivery & Emotion":

* Emotion/Tone (Multiple Sliders/Presets)

* Pitch (Slider)

* Pace/Speed (Slider)

* Volume/Loudness (Slider)

* Speech Style (Dropdown/Radio buttons)

* "Fine-Tuning & Nuance":

* Resonance/Depth (Slider)

* Clarity/Articulation (Slider)

* Breathiness (Slider)

* Vocal Texture (Dropdown/Checkboxes)

* Pause Duration (Slider)

* Intonation Variety (Slider)

  • Current Settings Summary: A small, dynamic text area displaying key current settings (e.g., "Female, Adult, American, Calm, Medium Pitch").
  • Presets/Inspiration:

* Dropdown to select from pre-defined voice archetypes (e.g., "Podcast Host," "News Announcer," "Friendly AI").

* Button: "Load Preset."

2.3 Right Panel: Preview & Actions

  • Header: "Preview & Manage"
  • Voice Name & Description Input:

* Text field for "Voice Name."

* Text area for "Voice Description."

  • Text Input for Preview:

* Large, multi-line text area (e.g., 5-8 lines) for users to type or paste text they want to hear.

* Placeholder text: "Enter text to preview your voice..."

* Character counter.

  • Audio Playback Controls:

* Play Button: Prominently displayed, initiates voice generation and playback.

* Stop Button: Stops current playback.

* Waveform Visualizer: A dynamic visual representation of the audio being played, updating in real-time or post-generation.

* Volume Slider: For preview playback volume.

* Progress Bar: Indicates generation and playback progress.

  • Action Buttons (Bottom of Right Panel):

* "Save Voice Profile": Saves the current voice configuration.

* "Generate Voice ID": Finalizes the voice and assigns a unique ID for API usage.

* "Clear All Settings": Resets all parameters to default.

* "Compare Voices": (Advanced feature) Opens a modal to compare current voice with a previously saved one.

  • Saved Voices List/Gallery (Collapsible/Tabbed):

* A section allowing users to view, load, edit, or delete their saved custom voices.

* Each entry shows Voice Name, key characteristics, and "Load," "Edit," "Delete" buttons.

2.4 Additional UI Elements

  • Tooltips: Hovering over any parameter or control will display a concise explanation of its function and impact.
  • Undo/Redo: Icons in a prominent position (e.g., top bar) for quick iteration.
  • Global Volume Control: For the entire application.
  • Help/FAQ Link: In the footer or header.

3. Color Palettes

The color palette aims for a professional, modern, and clean aesthetic, prioritizing readability and user comfort.

3.1 Primary Palette (PantheraHive Branding)

  • Primary Blue/Teal: #007BFF (or a similar vibrant, professional blue) - Used for primary buttons, active states, headers, and branding elements.
  • Dark Grey: #343A40 - For main text, icons, and strong borders.
  • Light Grey: #F8F9FA - For background elements, inactive states, and secondary text.
  • White: #FFFFFF - For main content areas, text fields, and clear space.

3.2 Accent & Feedback Palette

  • Accent Green: #28A745 - For success messages, positive feedback, and "Save" buttons.
  • Accent Orange/Yellow: #FFC107 - For warnings, attention-grabbing elements, and secondary accents.
  • Accent Red: #DC3545 - For error messages, delete actions, and critical alerts.
  • Highlight Cyan: #17A2B8 - For active sliders, interactive elements, and subtle highlights.

3.3 Accessibility Considerations

  • Ensure sufficient contrast ratios (WCAG 2.1 AA or AAA) between text and background colors.
  • Use distinct colors for interactive elements and feedback states.
  • Provide a dark mode option (optional, but highly recommended for extended use).

4. UX Recommendations

User experience is paramount for a tool as intricate as an AI voice designer. These recommendations ensure an intuitive, efficient, and satisfying design process.

4.1 Intuitive Interaction & Feedback

  • Real-time Visual Feedback: While voice generation isn't instant, sliders should provide immediate visual feedback. The waveform visualizer should animate during playback.
  • Clear Labeling & Tooltips: Every control, slider, and button must have a clear, concise label. Tooltips should offer additional context, examples, or explanations of how a parameter influences the voice.
  • Consistent UI Patterns: Use standard UI elements (sliders, dropdowns, radio buttons) that users are already familiar with.
  • Auditory Preview: Make the "Play" button prominent. Provide quick, short previews for rapid iteration, and allow for longer paragraph previews for final checks.
  • Progress Indicators: Clearly show when a voice is being generated or loaded to manage user expectations.

4.2 Iteration & Management

  • Undo/Redo Functionality: Essential for experimentation. Users should be able to easily revert changes or reapply them.
  • Save & Load Profiles: Allow users to save their unique voice configurations and load them for future use or modification.
  • Versioning (Optional but Recommended): For advanced users, allow saving multiple versions of a voice as they iterate.
  • Comparison Mode: Enable users to listen to two different voice profiles side-by-side or toggle between them to discern subtle differences.
  • Default & Reset Options: Each parameter should have a default setting, and a "Reset All" button should be available.

4.3 Guidance & Accessibility

  • Onboarding/Quick Start: For first-time users, offer a brief tour or a "Quick Start" wizard to guide them through the basic steps of voice design.
  • Preset Voices: Provide a gallery of professionally designed voice presets to serve as starting points or inspiration.
  • Contextual Help: Integrate "i" (information) icons next to complex parameters that link to more detailed documentation or examples.
  • Keyboard Navigation: Ensure the entire interface is navigable and operable via keyboard for accessibility.
  • Error Handling: Provide clear, actionable error messages if voice generation fails or parameters are out of range.

4.4 Performance & Responsiveness

  • Optimized Performance: Ensure the UI is highly responsive, with minimal lag when interacting with controls.
  • Fast Generation: While ElevenLabs handles the core, optimize the integration to minimize latency between hitting "Play" and hearing the audio.
  • Mobile Responsiveness: (If applicable) Design the interface to be fully responsive and usable on various screen sizes, potentially collapsing panels or simplifying controls for smaller devices.

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

ai_voice_designer.md
Download as Markdown
Copy all content
Full output as text
Download ZIP
IDE-ready project ZIP
Copy share link
Permanent URL for this run
Get Embed Code
Embed this result on any website
Print / Save PDF
Use browser print dialog
\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);}});}