import { useState } from „react“;
const TONES = [
{ v: „motivierend“, label: „Motivierend“ },
{ v: „humorvoll“, label: „Humorvoll“ },
{ v: „informativ“, label: „Informativ“ },
{ v: „emotional“, label: „Emotional“ },
{ v: „provokativ“, label: „Provokativ“ },
{ v: „inspirierend“,label: „Inspirierend“},
];
export default function ReelGen() {
const [topic, setTopic] = useState(„“);
const [content, setContent] = useState(„“);
const [audience, setAudience] = useState(„“);
const [tone, setTone] = useState(„motivierend“);
const [dur, setDur] = useState(„30“);
const [lang, setLang] = useState(„Deutsch“);
const [htags, setHtags] = useState(„10“);
const [extra, setExtra] = useState(„“);
const [loading, setLoading] = useState(false);
const [result, setResult] = useState(null);
const [error, setError] = useState(„“);
const [copied, setCopied] = useState(false);
async function generate() {
if (!topic.trim() || !content.trim()) {
setError(„Bitte Thema und Kerninhalt ausfüllen.“);
return;
}
setError(„“);
setResult(null);
setLoading(true);
const prompt =
`Du bist ein erfahrener Social-Media-Content-Creator für virale Instagram Reels.\n\n` +
`Erstelle ein vollständiges Reel-Script auf ${lang}:\n` +
`- Thema: ${topic}\n` +
`- Inhalt: ${content}\n` +
`- Zielgruppe: ${audience || "Allgemein"}\n` +
`- Ton: ${tone}\n` +
`- Länge: ca. ${dur} Sekunden\n` +
`- Hashtags: ${htags} Stück\n` +
(extra ? `- Sonderwunsch: ${extra}\n` : "") +
`\nAntworte NUR als valides JSON ohne Markdown oder Backticks:\n` +
`{"hook":"...","script":"...","caption":"...","hashtags":["tag1","tag2"],"cta":"...","tips":"..."}`;
try {
const res = await fetch("https://api.anthropic.com/v1/messages", {
method: "POST",
headers: {
"Content-Type": "application/json",
"anthropic-version": "2023-06-01",
"anthropic-dangerous-direct-browser-access": "true",
},
body: JSON.stringify({
model: "claude-sonnet-4-20250514",
max_tokens: 1200,
messages: [{ role: "user", content: prompt }],
}),
});
const data = await res.json();
if (data.error) throw new Error(data.error.message);
const raw = (data.content || []).map(b => b.text || "").join("");
const match = raw.replace(/```json|```/g, "").trim().match(/\{[\s\S]*\}/);
if (!match) throw new Error("Kein JSON in der Antwort gefunden.");
setResult(JSON.parse(match[0]));
} catch (e) {
setError(e.message || "Unbekannter Fehler.");
} finally {
setLoading(false);
}
}
function toPlain() {
if (!result) return „“;
const tags = (result.hashtags || []).map(h => „#“ + h.replace(/^#/, „“)).join(“ „);
return HOOK\n${result.hook}\n\nSCRIPT\n${result.script}\n\nCTA\n${result.cta}\n\nCAPTION\n${result.caption}\n\nHASHTAGS\n${tags}\n\nTIPPS\n${result.tips};
}
function copyAll() {
navigator.clipboard.writeText(toPlain()).then(() => {
setCopied(true);
setTimeout(() => setCopied(false), 2000);
});
}
const S = {
wrap: { fontFamily: „system-ui,sans-serif“, maxWidth: 780, margin: „0 auto“, padding: „28px 16px 50px“, color: „var(–color-text-primary)“ },
hdr: { display: „flex“, alignItems: „center“, justifyContent: „space-between“, marginBottom: 28 },
logoRow: { display: „flex“, alignItems: „center“, gap: 10 },
logoSq: { width: 34, height: 34, background: „linear-gradient(135deg,#ff4570,#8b5cf6)“, borderRadius: 9, display: „grid“, placeItems: „center“, fontSize: 16 },
logoName: { fontSize: 18, fontWeight: 700, letterSpacing: -0.5 },
pill: { fontSize: 11, color: „var(–color-text-secondary)“, border: „0.5px solid var(–color-border-secondary)“, padding: „3px 10px“, borderRadius: 99 },
grid: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: 13, marginBottom: 13 },
box: { background: "var(--color-background-secondary)", border: "0.5px solid var(--color-border-tertiary)", borderRadius: "var(--border-radius-lg)", padding: 20 },
boxFull: { gridColumn: "1/-1", background: "var(--color-background-secondary)", border: "0.5px solid var(--color-border-tertiary)", borderRadius: "var(--border-radius-lg)", padding: 15 },
lbl: { display: "block", fontSize: 11, color: "var(--color-text-secondary)", marginBottom: 6, textTransform: "uppercase", letterSpacing: 1 },
f: { marginBottom: 12 },
inp: { width: "100%", fontSize: 14 },
ta: { width: "100%", fontSize: 14, minHeight: 72, resize: "vertical" },
sel: { width: "100%", fontSize: 14 },
two: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: 10 },
tags: { display: "flex", flexWrap: "wrap", gap: 6, marginTop: 6 },
tag: (on) => ({
background: on ? "var(--color-background-info)" : "var(--color-background-primary)",
border: `0.5px solid ${on ? "var(--color-border-info)" : "var(--color-border-secondary)"}`,
color: on ? "var(--color-text-info)" : "var(--color-text-secondary)",
borderRadius: 99, padding: "5px 11px", fontSize: 12,
cursor: "pointer", userSelect: "none",
}),
btn: { width: "100%", padding: "13px 0", background: "linear-gradient(135deg,#ff4570,#8b5cf6)", border: "none", borderRadius: "var(--border-radius-lg)", color: "#fff", fontSize: 15, fontWeight: 700, cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center", gap: 8 },
btnDis: { opacity: 0.45, cursor: "not-allowed" },
outWrap: { background: "var(--color-background-secondary)", border: "0.5px solid var(--color-border-tertiary)", borderRadius: "var(--border-radius-lg)", overflow: "hidden" },
outHdr: { display: "flex", alignItems: "center", justifyContent: "space-between", padding: "12px 20px", borderBottom: "0.5px solid var(--color-border-tertiary)" },
outTtl: { fontSize: 11, color: "var(--color-text-secondary)", textTransform: "uppercase", letterSpacing: 1.5 },
acts: { display: "flex", gap: 7 },
btnS: (ok) => ({ fontSize: 11, color: ok ? "var(--color-text-success)" : "var(--color-text-secondary)", border: `0.5px solid ${ok ? "var(--color-border-success)" : "var(--color-border-secondary)"}`, borderRadius: 7, padding: "5px 10px", cursor: "pointer", background: "transparent" }),
outBody: { padding: 22, minHeight: 150, maxHeight: 480, overflowY: "auto" },
empty: { display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", padding: "44px 0", gap: 10, color: "var(--color-text-secondary)" },
loading: { display: "flex", alignItems: "center", justifyContent: "center", gap: 12, padding: "44px 0", color: "var(--color-text-secondary)", fontSize: 13 },
sec: { marginBottom: 20 },
secLbl: { fontSize: 10, color: "var(--color-text-tertiary)", textTransform: "uppercase", letterSpacing: 2, marginBottom: 8, display: "flex", alignItems: "center", gap: 8 },
secLine:{ flex: 1, height: 1, background: "var(--color-border-tertiary)" },
hookTxt: { fontSize: 20, fontWeight: 700, lineHeight: 1.25, color: "var(--color-text-primary)" },
bodyTxt: { fontSize: 14, lineHeight: 1.7, color: "var(--color-text-secondary)" },
ctaTxt: { fontSize: 15, fontWeight: 500, color: "var(--color-text-success)", lineHeight: 1.5 },
capTxt: { fontSize: 14, lineHeight: 1.7, color: "var(--color-text-secondary)", whiteSpace: "pre-wrap" },
tagList: { display: "flex", flexWrap: "wrap", gap: 6 },
hChip: { background: "var(--color-background-info)", color: "var(--color-text-info)", border: "0.5px solid var(--color-border-info)", borderRadius: 99, padding: "3px 10px", fontSize: 11 },
tipLine: { fontSize: 13, color: "var(--color-text-secondary)", marginBottom: 6, paddingLeft: 12, borderLeft: "2px solid var(--color-border-tertiary)", lineHeight: 1.55, borderRadius: 0 },
err: { color: "var(--color-text-danger)", fontSize: 12, padding: "10px 14px", marginTop: 10, background: "var(--color-background-danger)", border: "0.5px solid var(--color-border-danger)", borderRadius: "var(--border-radius-md)" },
cc: { fontSize: 10, color: "var(--color-text-tertiary)", textAlign: "right", marginTop: 4 },
};
function Sec({ label, children }) {
return (
{label}
{children}
);
}
return (
🎬
ReelGen
AI Powered
<div style={S.grid}>
{/* Inhalt */}
<div style={S.box}>
<div style={{...S.lbl, marginBottom:14}}>Thema & Inhalt</div>
<div style={S.f}>
<label style={S.lbl}>Thema / Nische</label>
<input style={S.inp} type="text" placeholder="Fitness, Business, Kochen …" value={topic} onChange={e=>setTopic(e.target.value)}/>
</div>
<div style={S.f}>
<label style={S.lbl}>Kerninhalt</label>
<textarea style={S.ta} placeholder="Worum geht es konkret?" value={content} onChange={e=>{ if(e.target.value.length<=500) setContent(e.target.value); }}/>
<div style={S.cc}>{content.length}/500</div>
</div>
<div style={S.f}>
<label style={S.lbl}>Zielgruppe</label>
<input style={S.inp} type="text" placeholder="z.B. Unternehmer, Frauen 25–35 …" value={audience} onChange={e=>setAudience(e.target.value)}/>
</div>
</div>
{/* Stil */}
<div style={S.box}>
<div style={{...S.lbl, marginBottom:14}}>Stil & Format</div>
<div style={S.f}>
<label style={S.lbl}>Ton</label>
<div style={S.tags}>
{TONES.map(t=>(
<div key={t.v} style={S.tag(tone===t.v)} onClick={()=>setTone(t.v)}>{t.label}</div>
))}
</div>
</div>
<div style={S.f}>
<label style={S.lbl}>Reel-Länge</label>
<select style={S.sel} value={dur} onChange={e=>setDur(e.target.value)}>
<option value="15">~15 Sek – Super kurz</option>
<option value="30">~30 Sek – Standard</option>
<option value="60">~60 Sek – Detailliert</option>
<option value="90">~90 Sek – Deep Dive</option>
</select>
</div>
<div style={S.f}>
<div style={S.two}>
<div>
<label style={S.lbl}>Sprache</label>
<select style={S.sel} value={lang} onChange={e=>setLang(e.target.value)}>
<option value="Deutsch">Deutsch</option>
<option value="Englisch">Englisch</option>
<option value="Spanisch">Spanisch</option>
<option value="Französisch">Französisch</option>
</select>
</div>
<div>
<label style={S.lbl}>Hashtags</label>
<select style={S.sel} value={htags} onChange={e=>setHtags(e.target.value)}>
<option value="5">5 Stück</option>
<option value="10">10 Stück</option>
<option value="20">20 Stück</option>
<option value="30">30 Stück</option>
</select>
</div>
</div>
</div>
<div>
<label style={S.lbl}>Extra-Wunsch (optional)</label>
<input style={S.inp} type="text" placeholder="z.B. Story einbauen …" value={extra} onChange={e=>setExtra(e.target.value)}/>
</div>
</div>
{/* Button */}
<div style={S.boxFull}>
<button style={{...S.btn,...(loading?S.btnDis:{})}} onClick={generate} disabled={loading}>
{loading ? "Generiere …" : "✦ Reel Script generieren"}
</button>
{error && <div style={S.err}>⚠ {error}</div>}
</div>
</div>
{/* Output */}
<div style={S.outWrap}>
<div style={S.outHdr}>
<div style={S.outTtl}>Output</div>
{result && (
<div style={S.acts}>
<button style={S.btnS(copied)} onClick={copyAll}>{copied ? "✓ Kopiert" : "Kopieren"}</button>
<button style={S.btnS(false)} onClick={generate}>↻ Neu</button>
</div>
)}
</div>
<div style={S.outBody}>
{loading && (
<div style={S.loading}>
<div style={{width:18,height:18,border:"2px solid #ccc",borderTopColor:"#ff4570",borderRadius:"50%",animation:"spin .75s linear infinite"}}/>
<span>Script wird erstellt …</span>
<style>{`@keyframes spin{to{transform:rotate(360deg)}}`}</style>
</div>
)}
{!loading && !result && (
<div style={S.empty}>
<div style={{fontSize:30,opacity:.35}}>🎞️</div>
<div style={{fontSize:13,opacity:.45}}>Formular ausfüllen und Generieren klicken</div>
</div>
)}
{!loading && result && (
<>
<Sec label="Hook"><div style={S.hookTxt}>{result.hook}</div></Sec>
<Sec label="Script"><div style={S.bodyTxt}>{result.script.split("\n").map((l,i)=><span key={i}>{l}<br/></span>)}</div></Sec>
<Sec label="CTA"><div style={S.ctaTxt}>{result.cta}</div></Sec>
<Sec label="Caption"><div style={S.capTxt}>{result.caption}</div></Sec>
<Sec label="Hashtags">
<div style={S.tagList}>
{(result.hashtags||[]).map((h,i)=>(
<div key={i} style={S.hChip}>#{h.replace(/^#/,"")}</div>
))}
</div>
</Sec>
<Sec label="Produktionstipps">
{result.tips.split("\n").filter(Boolean).map((t,i)=>(
<div key={i} style={S.tipLine}>{t}</div>
))}
</Sec>
</>
)}
</div>
</div>
</div>
);
}
Pinterest Pin Generator
Create Stunning Pins in Seconds
