diff --git a/server/prompts.mjs b/server/prompts.mjs
index 18113fc..e3f9d6a 100644
--- a/server/prompts.mjs
+++ b/server/prompts.mjs
@@ -33,24 +33,20 @@ REQUIRED JSON STRUCTURE:
"video_prompts": [
{
"type": "Abstract",
- "prompt": "5-second seamless loop, 16:9 aspect ratio. Abstract visuals: particles, fluid colors, geometric shapes, motion graphics. Specify: scene, camera angle, camera movement (slow pan/zoom/static), color palette (2-3 colors only), light source, motion quality. Must loop seamlessly (first frame = last frame). If using reverse playback, only use elements that make physical sense in reverse (e.g. pulsing light, expanding rings — NOT falling rain or rising smoke). Mood must match the song. Negative: text, watermark, logo, flash, abrupt cuts, camera shake, faces, hands, distortion, blur",
- "tool_recommendation": "Tool name(s) + one-sentence reason why they suit this prompt"
+ "prompt": "5-second seamless loop, 16:9 aspect ratio. Abstract visuals: particles, fluid colors, geometric shapes, motion graphics. Specify: scene, camera angle, camera movement (slow pan/zoom/static), color palette (2-3 colors only), light source, motion quality. Must loop seamlessly (first frame = last frame). If using reverse playback, only use elements that make physical sense in reverse (e.g. pulsing light, expanding rings — NOT falling rain or rising smoke). Mood must match the song. Negative: text, watermark, logo, flash, abrupt cuts, camera shake, faces, hands, distortion, blur"
},
{
"type": "Cinematic",
- "prompt": "5-second seamless loop, 16:9 aspect ratio. Real-world environment: landscape, weather, architecture, nature. Specify: scene, camera angle, camera movement, color palette (2-3 colors), light source, motion quality. Loopable (first frame = last frame). If elements move (rain, wind, water, fire), they must move in a physically correct direction — do NOT suggest rain or smoke as reversible loops. Negative: text, watermark, logo, flash, abrupt cuts, camera shake, faces, hands, distortion, blur",
- "tool_recommendation": "Tool name(s) + one-sentence reason"
+ "prompt": "5-second seamless loop, 16:9 aspect ratio. Real-world environment: landscape, weather, architecture, nature. Specify: scene, camera angle, camera movement, color palette (2-3 colors), light source, motion quality. Loopable (first frame = last frame). If elements move (rain, wind, water, fire), they must move in a physically correct direction — do NOT suggest rain or smoke as reversible loops. Negative: text, watermark, logo, flash, abrupt cuts, camera shake, faces, hands, distortion, blur"
},
{
"type": "Hybrid",
- "prompt": "5-second seamless loop, 16:9 aspect ratio. Blend of real and abstract: e.g. real environment with overlaid light effects, particle overlays on landscape, or a semi-abstract architectural scene. Loopable. Negative: text, watermark, logo, flash, abrupt cuts, camera shake, faces, hands, distortion, blur",
- "tool_recommendation": "Tool name(s) + one-sentence reason"
+ "prompt": "5-second seamless loop, 16:9 aspect ratio. Blend of real and abstract: e.g. real environment with overlaid light effects, particle overlays on landscape, or a semi-abstract architectural scene. Loopable. Negative: text, watermark, logo, flash, abrupt cuts, camera shake, faces, hands, distortion, blur"
}
]
}
-Keep each video_prompts[].prompt under 900 characters (excluding the Negative line).
-Recommended video tools (choose the best fit per prompt): {{VIDEO_TOOLS}}. Never recommend Sora.`,
+Keep each video_prompts[].prompt under 900 characters (excluding the Negative line).`,
partial: `You are a music production assistant specializing in Suno AI song creation.
The user has an existing song and wants to regenerate ONE section. Output ONLY
@@ -78,8 +74,8 @@ QUALITY CONSTRAINTS:
ABAB rhyme. No references to instruments, genre, or music production.
- style: comma-separated, max 120 words, include tempo + BPM range, never
name an artist, no "sounds like" phrases.
-- video_prompts: 5-second seamless loops, 16:9. Include the "Negative" line
- inside each prompt. Keep prompts under 900 characters. Recommended tools: {{VIDEO_TOOLS}}. Never recommend Sora.
+- video_prompts: short seamless loops, 16:9. Include the "Negative" line
+ inside each prompt. Keep prompts under 900 characters.
- youtube_description: follow the hook → description → divider → lyrics →
divider → CTA → hashtags structure.`,
style_normal: `You are a Suno style-prompt generator.
@@ -157,7 +153,7 @@ function getToolsString() {
export function buildSystemPrompt(req) {
const toolsStr = getToolsString();
-
+
if (req.section === 'lyrics_partial') {
return activePrompts.lyrics_partial;
}
diff --git a/src/components/cards/VideoPromptsCard.tsx b/src/components/cards/VideoPromptsCard.tsx
index db7fe0e..dca3987 100644
--- a/src/components/cards/VideoPromptsCard.tsx
+++ b/src/components/cards/VideoPromptsCard.tsx
@@ -11,6 +11,7 @@ import {
} from "../../lib/types";
import { useVideoAiLinks } from "../../lib/useVideoAiLinks";
import { faExternalLinkAlt } from "@fortawesome/free-solid-svg-icons";
+import { useToast } from "../../lib/toast";
interface VideoPromptsCardProps {
prompts: VideoPrompt[];
@@ -37,6 +38,36 @@ export function VideoPromptsCard({
const ref = useAutoHeight(current?.prompt ?? "", 120);
const { links } = useVideoAiLinks();
+ const toast = useToast();
+
+ const handleToolClick = async (url: string) => {
+ if (!current) return;
+
+ // Copy the prompt to clipboard (with negative prompt if applicable)
+ const textToCopy = `Prompt: ${current.prompt}\n\nNegative: ${NEGATIVE_VIDEO_PROMPT}`;
+ try {
+ await navigator.clipboard.writeText(textToCopy);
+ toast.success("Prompt copied to clipboard!");
+ } catch {
+ // Fallback
+ const ta = document.createElement("textarea");
+ ta.value = textToCopy;
+ ta.style.position = "fixed";
+ ta.style.opacity = "0";
+ document.body.appendChild(ta);
+ ta.select();
+ try {
+ document.execCommand("copy");
+ toast.success("Prompt copied to clipboard!");
+ } catch {
+ toast.error("Failed to copy prompt");
+ }
+ document.body.removeChild(ta);
+ }
+
+ // Open the tool in a new tab
+ window.open(url, "_blank", "noopener,noreferrer");
+ };
return (
- → Best for:{" "} - - {current.tool_recommendation} - -
-Negative @@ -122,16 +146,16 @@ export function VideoPromptsCard({ {links && links.length > 0 && (
)}