# MelodyMuse Generate all assets needed for a Suno AI song from a free-text description — titles, lyrics, style prompt, video prompts (Abstract / Cinematic / Hybrid), and a YouTube description, then download everything as a ZIP. The app runs **entirely in your browser** as a single static SPA. There is no backend, no database, no third-party services: the only network calls are direct `fetch` requests from your browser to the AI provider's OpenAI-compatible `/chat/completions` endpoint, using credentials that you paste into the Settings page. Those credentials are kept in this browser's `localStorage`. ## Features - 🎵 **All 5 Suno assets in one click** — titles, lyrics, style, video prompts, YouTube description - ✏️ **Inline editing** — every generated field is editable; revert any edit with one click - 🔄 **Per-section regeneration** — regenerate just one section; the rest of the song is passed as context for consistency - ⏱ **Elapsed-time counter** + ❌ **Cancel** button for long generations - 🕘 **Recent generations** — last 6 are kept in localStorage; one click to reload - ⌨️ **Keyboard shortcut** — `Cmd/Ctrl + Enter` to generate - 🎲 **Try an example** — fill the input with a random sample idea - 🌗 **Dark / light mode** — toggle in the header, persisted - 💾 **Standalone** — no backend, no signup, no telemetry ## Tech stack - React 18 + TypeScript + Vite - Tailwind CSS (dark by default, light theme via `html.light`) - JSZip for client-side ZIP generation - `react-router-dom` for the two routes (`/`, `/settings`) ## Repository layout ``` MelodyMuse/ ├── src/ │ ├── App.tsx │ ├── main.tsx │ ├── index.css # Tailwind layers + design-system components │ ├── components/ # UI building blocks │ │ ├── cards/ # The five result cards │ │ ├── ConfigBanner.tsx │ │ ├── CopyButton.tsx │ │ ├── EqualizerIcon.tsx │ │ ├── Footer.tsx │ │ ├── HistoryPanel.tsx │ │ ├── InputPanel.tsx │ │ ├── ResultCard.tsx │ │ ├── ResultsPanel.tsx │ │ ├── SkeletonCard.tsx │ │ ├── StickyZipBar.tsx │ │ └── ThemeToggle.tsx │ ├── pages/ # HomePage, SettingsPage │ ├── lib/ │ │ ├── history.ts # recent-generations persistence │ │ ├── llm.ts # direct fetch → provider, JSON extraction, config persistence │ │ ├── prompts.ts # system + user prompt construction │ │ ├── theme.ts # dark/light mode │ │ ├── toast.tsx # toast context │ │ ├── types.ts # shared TypeScript types + SECTION_LABELS │ │ ├── useAutoHeight.ts # shared textarea auto-grow hook │ │ ├── useElapsed.ts # shared "X seconds elapsed" hook │ │ └── zip.ts # JSZip layout │ └── vite-env.d.ts ├── public/favicon.svg ├── index.html ├── tailwind.config.js ├── vite.config.ts ├── tsconfig*.json └── package.json ``` ## Getting started 1. **Install dependencies** ```sh npm install ``` 2. **Start the dev server** ```sh npm run dev ``` Open in your browser. 3. **Open Settings** and fill in: - **API Endpoint URL** — e.g. `https://api.minimax.chat/v1` - **API Key** — your provider's secret key - **Model Name** — e.g. `MiniMax-M3` Click **Save Configuration**, then **Test Connection** to confirm everything is wired up. **Test Connection** uses your unsaved form values — your changes are only persisted when you click **Save**. 4. **Generate**. Return to the home page, type a music idea, click **Generate Song Assets** (or press `Cmd/Ctrl + Enter`). ## Build for production ```sh npm run build ``` Outputs static assets in `dist/`. The `dist/` folder is a normal SPA — serve it from any static host (GitHub Pages, Netlify, Vercel, `python -m http.server`, …). > ⚠️ **Heads up about deployment.** Because the API key is stored in the > browser's `localStorage`, you should not serve a public deployment of this > app and use it with a real key on a shared device. For personal/local use > this is fine. ## CORS The app makes direct cross-origin requests from the browser to your provider. If your provider does not send the right `Access-Control-Allow-*` headers for your origin, the request will fail with a CORS error. The generated error message will explicitly call this out. Workarounds: - Pick a provider/endpoint that already permits browser CORS (most managed OpenAI-compatible services do). - Run the app on the same origin as the API (i.e. front it with a tiny proxy). - Use a CORS-permissive browser extension during local development. ## Provider format The configured endpoint must expose an OpenAI-compatible `POST {api_endpoint}/chat/completions` route that accepts `{ model, messages, max_tokens }` and returns `{ choices: [{ message: { content } }] }`. ## Security notes - The API key is held in `localStorage` and is only sent to the endpoint you configure. No analytics, no telemetry, no third-party calls. - Three localStorage keys are used: - `melodymuse-config` — `{ api_endpoint, api_key, model_name }` - `melodymuse-history` — the last 6 generations (input + assets) - `melodymuse-theme` — `'dark' | 'light'` - You can clear them at any time from your browser's devtools (Application → Local Storage). ## License Personal use. Do whatever you want with it.