Template React 1 page MIT
Suna Studio
A production-ready single-page React + TypeScript AI music studio that generates real songs through Suna AI's public Hugging Face Space via @gradio/client. A prompt-first composer (Simple/Custom modes, six artist presets, editable lyrics, a Turbo/High-Fidelity synthesis engine switch, 24-68s length, optional sing-to-masterpiece vocal upload with a vocal/band mix) feeds the Space's live generate_suna_track endpoint; results land in a session-only library with a Spotify-style near-violet player bar (play/pause, seek, volume, MediaSession metadata), interactive mobile player sheet, telemetry and sung-lyric sheets, and WAV-master downloads. Soft lavender/white palette with a violet accent and honest live states - no fake progress bars.
- React
- TSX
- Tailwind CSS
- soft-lavender-studio
- Pages
- 1 page
- Stack
- React + TSX
- Theme
- Light only
- Responsive
- Yes
- Files
- 35
- License
- MIT
Preview
The whole site, live.
Scroll inside the frame, switch viewports, or open the raw preview in a new tab — it is the same file the CLI installs.
devsnips.site/templates/react/suna-ai-studio/ What's inside
Everything the folder ships.
Straight from the registry's metadata — every line maps to a file you can open in the source tabs below.
- real AI music generation through Suna AI's public Space via @gradio/client v2 (/gradio_api/info availability probe, /generate_suna_track endpoint)
- prompt-first composer with Simple and Custom modes, ⌘/Ctrl+Enter submit, and 500-character prompt budget
- six artist presets (Indila Chanson, Matushka Folk-Pop, Power Ballad, Arena Rock, Afro-Latin Pop, Slap House) with the Space's exact API enum values
- editable lyrics editor with songbook autofill that matches the Space's preset-change behavior
- Turbo (8-step) / High-Fidelity (16-step) synthesis engine switch and 24-68s length slider mirroring the Space's controls
- optional sing-to-masterpiece vocal clip upload (drag & drop, 25MB budget, clip duration read) with a 0.30-1.20 vocal/band mix
- honest generation states - connecting, composing with a real elapsed timer, queue notices, and Space error text surfaced verbatim; no fabricated progress percentages
- session-only track library with rename, remove, clear, and copy-prompt; tracks never leave the tab and expire with the Space's temp files
- Spotify-style near-violet player bar with play/pause, seek slider, seek-ahead/behind, volume, mute toggle, and keyboard shortcuts
- MediaSession metadata (title, artist, album artwork) for OS media controls
- expansive NowPlaying card with track stats, Suna telemetry, and the Space's word-aligned sung-lyric sheet
- full-screen mobile player sheet (dialog, focus trap, Escape to close) and mobile session drawer
- downloads prefer the Space's 48 kHz 16-bit WAV master, falling back to the 320kbps MP3
- lavender/white design system: Plus Jakarta Sans + Fraunces, #F6F4FA paper, #211D31 ink, #6F52D9 violet accent, #151220 player
- semantics - landmark structure, aria-pressed chips, labeled sliders, role=status generation card, focus-visible rings, prefers-reduced-motion handling
Technical
Stack, scripts, structure.
Everything you need to know before you install.
vite tsc --noEmit && vite build vite preview tsc --noEmit root 12
-
.gitignoreother -
AGENTS.mddoc -
index.htmlcode -
metadata.jsonconfig -
package-lock.jsonconfig -
package.jsonconfig -
postcss.config.jscode -
preview.htmlpreview -
README.mddoc -
tailwind.config.tscode -
tsconfig.jsonconfig -
vite.config.tscode
src/ 23
-
App.tsxcode -
components/Composer.tsxcode -
components/GenerationPanel.tsxcode -
components/Icon.tsxcode -
components/MobileDrawer.tsxcode -
components/NowPlaying.tsxcode -
components/PlayerBar.tsxcode -
components/PlayerSheet.tsxcode -
components/Sidebar.tsxcode -
components/Slider.tsxcode -
components/SunaMark.tsxcode -
components/TopBar.tsxcode -
components/TrackArtwork.tsxcode -
components/TrackCard.tsxcode -
index.csscode -
lib/clipboard.tscode -
lib/focus.tscode -
lib/format.tscode -
lib/palettes.tscode -
lib/suna.tscode -
lib/types.tscode -
main.tsxcode -
studio/StudioProvider.tsxcode
Install
One command, whole folder.
Pulls the template into your project through the DevSnips CLI. The registry path below is stable across the CLI, MCP server and Skills.
npx devsnips add React/Templates/suna-ai-studio React/Templates/suna-ai-studio AI-ready
Hand the whole job to your agent — Cursor, Cline, Claude Code or Windsurf. One prompt installs the template, fixes the theme toggle, optimises it and reshapes it for what you are building.
Scaffold the DevSnips template "Suna Studio" (React/Templates/suna-ai-studio) into this project, then audit, fix and tailor it. 1. Install — if the DevSnips MCP server is connected, fetch the resource with get_resource(id="React/Templates/suna-ai-studio"). Otherwise run npx devsnips add React/Templates/suna-ai-studio and install the dependencies the template declares. 2. Audit — check the template end to end before changing anything: theme toggling (dark/light), responsive behaviour, accessibility, unused files and assets. 3. Fix — repair what the audit found, starting with the theme toggle: it must persist across reloads, never flash the wrong theme on first paint, and every component must read the same tokens in both modes. 4. Optimise and adapt — trim what the site does not need, then customise the template for the product being built here: replace the placeholder branding, copy, imagery, navigation and routes so it reads as this project rather than as a demo.
devsnips://templates/suna-ai-studio The same path the CLI, MCP server and Skills resolve — one registry, one resource URI.
Source
Read it before you ship it.
The README, manifest and entry document — verbatim, straight from the registry.
# Suna Studio Template
A production-ready, single-page **React + TypeScript AI music studio** that generates
**real songs** through [Suna AI's public Hugging Face Space](https://huggingface.co/spaces/johanjomet/suna-ai-studio)
via `@gradio/client`. The page is a prompt-first composer over a soft lavender dashboard,
with a Spotify-style dark player that plays, seeks, and downloads the Space's actual audio.
There is **no mock generation** in this template. Every track is rendered by the live
Space; every state (idle → connecting → composing → ready/unavailable) reflects the real
request, and the honest messages say exactly that.
## Highlights
- **Real generation** — `Client.connect("johanjomet/suna-ai-studio")` + `client.submit("/generate_suna_track", …)`.
- **Prompt-first composer** — Simple and Custom modes, idea chips, ⌘/Ctrl + ↵ submit, 500-char budget.
- **Six artist presets** — Indila Chanson, Matushka Folk-Pop, Power Ballad, Arena Rock, Afro-Latin Pop, Slap House — each stored with the Space's exact API values and its default songbook.
- **Editable lyrics** — the Custom mode exposes the same lyric sheet the Space edits; untouched songbooks follow preset changes just like the Space's UI.
- **Synthesis engine** — Turbo (8 steps) / High-Fidelity SFT (16 steps); **length** 24–68 s.
- **Sing-to-Masterpiece** — optional vocal clip (drop or browse, 25 MB) with a 0.30–1.20 vocal/band mix.
- **Honest states** — a real elapsed timer while the Space renders. Suna's queue exposes no progress percentage, and the UI says so instead of faking one. Space errors (quota, capacity, render failure) surface verbatim.
- **Session library** — tracks live in the tab only; rename, remove, clear, copy prompt.
- **Dark player bar** — near-violet bottom bar with play/pause, seek, ±10 s, volume, mute, MediaSession metadata; a full-screen mobile player sheet + session drawer.
- **Telemetry & lyrics** — the Space's studio telemetry and the word-aligned sung-lyric sheet are kept with each track.
- **Downloads** — prefer the 48 kHz 16-bit WAV master, fall back to the 320 kbps MP3.
## Design direction
**Soft lavender studio** — a calm instrument panel around a serious dark player:
- **Type:** Plus Jakarta Sans (UI, 400–800) + Fraunces (display).
- **Palette:** paper `#F6F4FA`, ink `#211D31`, violet accent `#6F52D9`, night player `#151220`, soft cream `#F5F1FF`.
- **Composition:** rounded 26px cards on a paper canvas, a sidebar + top bar shell, a featured track card that grows out of the composer, and the fixed near-violet player at the bottom. No glassmorphism, no neon, no decorative clutter.
The visual system lives entirely in `tailwind.config.ts` (colors, fonts), `src/index.css`
(tokens, range styling, dialog/drawer rules), and the presentational components — it does
not depend on the shared DevSnips `--ds-*` tokens.
## Structure
```text
suna-ai-studio/
├── index.html # Vite entry (theme-color, root mount)
├── package.json # React 18, @gradio/client 2, Vite 5
├── vite.config.ts
├── tailwind.config.ts # lavender/white color system, fonts, animations
├── postcss.config.js
├── tsconfig.json # strict TypeScript
└── src/
├── main.tsx # StrictMode + StudioProvider mount
├── App.tsx # shell: TopBar, Sidebar, composer, session feed, footer
├── index.css # CSS tokens, range styling, dialog/drawer rules
├── lib/
│ ├── suna.ts # Gradio API adapter: presets, generate, probe, download
│ ├── types.ts # Track, SunaGenerateInput, generation + error types
│ ├── palettes.ts # artwork palettes
│ ├── format.ts # time/bytes helpers + titleFromPrompt
│ ├── clipboard.ts # copy helper
│ └── focus.ts # focus/keyboard helpers
├── studio/
│ └── StudioProvider.tsx # audio element, generation lifecycle, session state
└── components/
├── Composer.tsx # Simple/Custom prompt-first composer
├── GenerationPanel.tsx# honest generation status card
├── TrackCard.tsx # featured + compact track cards
├── NowPlaying.tsx # expanded current-track panel
├── PlayerBar.tsx # dark bottom player
├── PlayerSheet.tsx # mobile full-screen player dialog
├── Sidebar.tsx # session tracklist (desktop + drawer content)
├── TopBar.tsx # brand + availability status
├── MobileDrawer.tsx # mobile session drawer
├── SunaMark.tsx # brand mark (SVG)
├── TrackArtwork.tsx # generated per-track artwork
├── Slider.tsx # accessible range styling
└── Icon.tsx # inline icon set
```
## Setup & run
Requires Node.js + npm. From the template root:
```bash
npm install
npm run dev # Vite dev server — open the printed URL (usually http://localhost:5173)
```
Production build + local preview:
```bash
npm run build # tsc type-check + Vite production build → dist/
npm run preview # serve the built app
```
**Static preview:** `preview.html` at the template root is a self-contained static
prototype of the studio shell (Tailwind CDN + the real palette, composer, and dark player
chrome). It **cannot** generate audio — generation is intentionally disabled in the
preview, and the preview says so. Only the installed app talks to the Space.
## The Suna API contract
Everything lives in `src/lib/suna.ts`. Verified against
`https://johanjomet-suna-ai-studio.hf.space/gradio_api/info` + the Space's source (2026-10):
- `POST /gradio_api/call/v2/generate_suna_track`
- params (in order): `user_prompt` (str) · `artist_preset` (exact enum string) ·
`custom_lyrics` (str, empty = the preset's songbook) · `duration_sec` (24–68 slider,
server clips 20–68) · `speed_mode` (Turbo | High-Fidelity SFT enum string) ·
`uploaded_vocal` (optional fingerprint/file) · `vocal_mix` (0.30–1.20, step 0.05)
- returns `[mp3 FileData, wav FileData, telemetry string, lyricSheet string]`;
render errors return `[null, null, "⚠️ …", lyrics]`.
- `GET …/gradio_api/info` is used as the availability probe (`/generate_suna_track` must
exist in `named_endpoints`).
The audio file URLs are Space-hosted `…/gradio_api/file=/tmp/gradio/…` links; they expire
with the Space's temp storage, which is why the library is session-only and downloads are
encouraged.
**Know the external limits.** The Space runs on ZeroGPU with an anonymous run quota; when
the quota is spent for your connection the queue may close with no events — the template
says so honestly and asks you to retry later. Streaming the returned audio from the page
works because the Space sends CORS headers (verified).
## Customization
- **Palette & fonts:** defined once in `tailwind.config.ts` + the token block at the top of `src/index.css`.
- **Presets:** `SUNA_PRESETS` in `src/lib/suna.ts` — ids, labels, palettes, and the default songbook the composer autofills. Keep the `apiValue` strings byte-exact.
- **Engine modes:** `SUNA_QUALITY_MODES`, same byte-exact rule.
- **Copy/ideas:** the `IDEAS` array in `src/components/Composer.tsx` and the shell copy in `src/App.tsx`.
- **Host change:** if you fork/deploy the Space, change the constants at the top of `src/lib/suna.ts` (`SUNA_SPACE_ID`, `SUNA_HOST`).
## Accessibility
- Landmark structure (`header`, `main`, `aside`, `footer`, `form`), single `h1`.
- All controls labeled: sliders (`aria-label`, `aria-valuetext`), toggles (`aria-pressed`/radio groups), player buttons with explicit names.
- Generation status card uses `role="status"`; toasts use a polite live region.
- Player sheet is a native `<dialog>` with focus on close control and Escape to dismiss; the drawer behaves the same.
- Global `:focus-visible` rings; `prefers-reduced-motion` disables floating/idle animations (verified in `src/index.css`).
## Browser support
Modern evergreen browsers. Playback uses native `HTMLAudioElement` with MediaSession;
generation requires WebSockets/SSE for the Gradio queue stream. {
"name": "suna-studio",
"private": true,
"version": "1.0.0",
"type": "module",
"description": "Suna Studio — a minimal AI music studio built with React, TypeScript, and Suna AI.",
"scripts": {
"dev": "vite",
"build": "tsc --noEmit && vite build",
"preview": "vite preview",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@gradio/client": "^2.7.1",
"react": "^18.3.1",
"react-dom": "^18.3.1"
},
"devDependencies": {
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@vitejs/plugin-react": "^4.3.1",
"autoprefixer": "^10.4.19",
"postcss": "^8.4.38",
"tailwindcss": "^3.4.4",
"typescript": "^5.5.2",
"vite": "^5.3.1"
}
} <!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="theme-color" content="#F6F4FA" />
<meta
name="description"
content="Suna Studio — describe a track and render it with Suna AI. A minimal, open React + TypeScript music studio by DevSnips."
/>
<link
rel="icon"
href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' rx='8' fill='%23201D19'/%3E%3Ccircle cx='16' cy='16' r='8' fill='%23E06A3B'/%3E%3Cpath d='M16 8c3.4 2.7 3.9 5.8 1.7 7.9-2.1 2-5.2 1.2-5.8 3.7-.5 2 .8 3.5 2.6 3.6' fill='none' stroke='%23FFF7EC' stroke-width='1.4' stroke-linecap='round'/%3E%3C/svg%3E"
/>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500&family=Instrument+Serif:ital@0;1&family=Inter:wght@400;500;600;700&display=swap"
rel="stylesheet"
/>
<title>Suna Studio — AI music, made simply</title>
</head>
<body>
<div id="root"></div>
<noscript>This studio needs JavaScript to generate and play music.</noscript>
<script type="module" src="/src/main.tsx"></script>
</body>
</html> # AGENTS.md — Suna Studio
Guidance for an AI agent adapting this template. Read this before editing.
## What this template is
A single-page **React + TypeScript AI music studio** that generates **real songs** through
Suna AI's public Hugging Face Space (`johanjomet/suna-ai-studio`) via `@gradio/client`.
It ships the full Vite project. Every track is rendered by the live Space — the template
contains no mock generation, no fake audio URLs, and no fabricated progress states.
## Design system
**Soft lavender studio** — Plus Jakarta Sans (UI) + Fraunces (display); palette paper
`#F6F4FA`, ink `#211D31`, violet accent `#6F52D9`, night player `#151220`, soft cream
`#F5F1FF`. Rounded prompt-first composer cards on a paper canvas, a sidebar + top-bar
shell, a featured track card, and a fixed near-violet Spotify-style player at the bottom.
No glassmorphism, no neon, no gradient-built decoration. The visual system lives entirely
in `tailwind.config.ts` (colors, fonts), the token block at the top of `src/index.css`,
and the presentational components — it does not depend on the shared DevSnips `--ds-*`
tokens.
## File layout
```
suna-ai-studio/
├── index.html # Vite entry (theme-color, root mount)
├── package.json # React 18, @gradio/client 2, Vite 5
├── vite.config.ts
├── tailwind.config.ts # lavender/white color system, fonts, animations
├── postcss.config.js
├── tsconfig.json # strict TypeScript
└── src/
├── main.tsx # StrictMode + StudioProvider mount
├── App.tsx # shell: TopBar, Sidebar, composer, session feed, footer
├── index.css # CSS tokens, range styling, dialog/drawer rules
├── lib/ # suna.ts (Gradio adapter), types.ts, palettes.ts,
│ format.ts, clipboard.ts, focus.ts
├── studio/
│ └── StudioProvider.tsx # audio element, generation lifecycle, session state
└── components/ # Composer, GenerationPanel, TrackCard, NowPlaying,
PlayerBar, PlayerSheet, Sidebar, TopBar, MobileDrawer,
SunaMark, TrackArtwork, Slider, Icon
```
## The external API (do not invent values)
`src/lib/suna.ts` is the single adapter. The contract was verified against the Space's
`/gradio_api/info` and its source (2026-10):
- endpoint `POST /gradio_api/call/v2/generate_suna_track`
- params in order: `user_prompt` · `artist_preset` · `custom_lyrics` · `duration_sec`
(Space slider 24–68, step 4) · `speed_mode` · `uploaded_vocal` (optional) ·
`vocal_mix` (0.30–1.20, step 0.05, default 0.88)
- returns `[mp3 FileData, wav FileData, telemetry string, lyricSheet string]`;
render errors return `[null, null, "⚠️ …", lyrics]`
- `artist_preset` and `speed_mode` take **byte-exact enum strings** (emoji included) —
they live in `SUNA_PRESETS` and `SUNA_QUALITY_MODES` and must never be paraphrased.
- availability probe: `GET /gradio_api/info` must contain `/generate_suna_track`
in `named_endpoints`.
Known external limits to preserve in copy: ZeroGPU anonymous run quota (the queue may
close with zero events when the quota is spent — surface that honestly), Space-hosted
temp file URLs that expire with the session (hence session-only tracks), and no progress
percentage from Suna (show a real elapsed timer, never a fake bar).
## How to adapt it
1. **Re-theme:** colors and fonts are defined once in `tailwind.config.ts` + the token block in `src/index.css`; swapping the palette re-colors every surface consistently.
2. **Copy and ideas:** edit the `IDEAS` array in `src/components/Composer.tsx` and the shell copy in `src/App.tsx`.
3. **Presets/engines:** edit `SUNA_PRESETS` / `SUNA_QUALITY_MODES` in `src/lib/suna.ts`, keeping the `apiValue` strings byte-exact and the preset `lyrics` matching the Space's songbooks.
4. **Different Space host:** change the constants at the top of `src/lib/suna.ts` (and re-verify the endpoint shape against that Space's `/gradio_api/info`).
5. **Run:** `npm install` → `npm run dev`; `npm run build` (strict `tsc` + Vite → `dist/`).
## Do not
- Do not mock generation, hardcode audio URLs, or fake progress percentages, timers, or telemetry strings — every visible state must come from a real request or an honest absence.
- Do not paraphrase the Gradio enum values, endpoint name, or parameter names.
- Do not persist tracks, prompts, or audio to local storage or a backend — the session lives in the tab only.
- Do not remove the honest quota/capacity messaging, the `role="status"` generation card, labeled sliders, or the focus-managed player sheet/drawer.
- Do not hand-edit generated DevSnips indexes; regenerate them with the repository's indexing scripts after structural changes.
## Quality bar
Semantics (`header`, `main`, `aside`, `footer`, `form`), single `h1`, all sliders/buttons
labeled with `aria-label` + `aria-valuetext`, toggles via `aria-pressed`/radio groups,
`role="status"` generation card, polite toast live region, native `<dialog>` surfaces with
Escape-to-close and known-focus close buttons, global `:focus-visible` rings,
`prefers-reduced-motion` handling, and no horizontal overflow down to 390px. Run
`npm run build` (strict `tsc` type-check) and `python3 scripts/tooling/validators/validate.py`
after changes.