From b62ede1bd62be5813f13f577ef4a998ff006f1ad Mon Sep 17 00:00:00 2001 From: Cosmo Date: Sun, 5 Jul 2026 20:55:45 -0400 Subject: [PATCH] =?UTF-8?q?feat:=20add=20/plugins=20page=20=E2=80=94=20age?= =?UTF-8?q?nt=20plugin=20marketplace=20showcase?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - New /plugins page showcasing all 4 Recoup plugins with install commands - Plugin cards with capabilities, skill counts, audience, GitHub links - Copy-to-clipboard install commands for Claude Code/Cowork/Codex/Cursor - How it works section (Install → Connect → Go) - CTA to docs and pricing - Added Plugins to header nav and footer product section - Copy extracted to lib/copy/plugins.ts (single source of truth pattern) --- app/plugins/layout.tsx | 17 +++ app/plugins/page.tsx | 234 +++++++++++++++++++++++++++++++++++++++++ lib/copy/plugins.ts | 125 ++++++++++++++++++++++ lib/nav.ts | 2 + 4 files changed, 378 insertions(+) create mode 100644 app/plugins/layout.tsx create mode 100644 app/plugins/page.tsx create mode 100644 lib/copy/plugins.ts diff --git a/app/plugins/layout.tsx b/app/plugins/layout.tsx new file mode 100644 index 0000000..24673f2 --- /dev/null +++ b/app/plugins/layout.tsx @@ -0,0 +1,17 @@ +import type { Metadata } from "next"; +import { buildPageMetadata } from "@/lib/seo"; + +export const metadata: Metadata = buildPageMetadata({ + title: "Agent Plugins for Music | Recoup", + description: + "Install Recoup plugins into Claude Code, Cowork, Codex, or Cursor. Artist research, content creation, catalog deals, and more — powered by the Recoup API.", + path: "/plugins", +}); + +export default function PluginsLayout({ + children, +}: { + children: React.ReactNode; +}) { + return <>{children}; +} diff --git a/app/plugins/page.tsx b/app/plugins/page.tsx new file mode 100644 index 0000000..b2f75e9 --- /dev/null +++ b/app/plugins/page.tsx @@ -0,0 +1,234 @@ +"use client"; + +import { useState, useEffect, useRef } from "react"; +import Link from "next/link"; +import { ArrowRight, Copy, Check, Terminal } from "lucide-react"; +import { pluginsCopy } from "@/lib/copy/plugins"; +import type { Plugin } from "@/lib/copy/plugins"; + +/* ── reveal-on-scroll ── */ +function useReveal() { + const ref = useRef(null); + const [v, setV] = useState(false); + useEffect(() => { + const el = ref.current; + if (!el) return; + const io = new IntersectionObserver( + ([e]) => { + if (e.isIntersecting) { + setV(true); + io.disconnect(); + } + }, + { threshold: 0.08 }, + ); + io.observe(el); + return () => io.disconnect(); + }, []); + return { + ref, + cls: `transition-all duration-[900ms] ease-[cubic-bezier(.16,1,.3,1)] ${ + v ? "opacity-100 translate-y-0" : "opacity-0 translate-y-10" + }`, + }; +} + +/* ── copy button ── */ +function CopyButton({ text }: { text: string }) { + const [copied, setCopied] = useState(false); + return ( + + ); +} + +/* ── plugin card ── */ +function PluginCard({ plugin, index }: { plugin: Plugin; index: number }) { + const { ref, cls } = useReveal(); + return ( +
+
+ {/* Header */} +
+
+

{plugin.name}

+ + {plugin.skillCount} skill{plugin.skillCount !== 1 ? "s" : ""} + {" · "} + {plugin.audience} + +
+ + GitHub → + +
+ + {/* Description */} +

+ {plugin.description} +

+ + {/* Capabilities */} +
    + {plugin.capabilities.map((cap) => ( +
  • + + {cap} +
  • + ))} +
+ + {/* Install command */} +
+ + {plugin.installCommand} + +
+
+
+ ); +} + +/* ── step card ── */ +function StepCard({ + step, + index, +}: { + step: (typeof pluginsCopy.steps)[number]; + index: number; +}) { + const { ref, cls } = useReveal(); + return ( +
+
+
+ {step.number} +
+

{step.title}

+

+ {step.description} +

+
+
+ ); +} + +/* ── page ── */ +export default function PluginsPage() { + const c = pluginsCopy; + + return ( +
+ {/* Hero */} +
+
+ Plugin Marketplace +
+

+ {c.title} +

+

+ {c.subtitle} +

+ + {/* Compatible-with badges */} +
+ {c.compatibleWith.map((tool) => ( + + {tool} + + ))} +
+
+ + {/* Plugin grid */} +
+ {c.plugins.map((plugin, i) => ( + + ))} +
+ + {/* How it works */} +
+

+ How it works +

+
+ {c.steps.map((step, i) => ( + + ))} +
+
+ + {/* CTA */} +
+
+

+ Ready to plug in? +

+

+ Get your API key, install a plugin, and let your AI agent run your + music business. +

+
+ + Get API Key + + + View Pricing + +
+
+
+
+ ); +} diff --git a/lib/copy/plugins.ts b/lib/copy/plugins.ts new file mode 100644 index 0000000..2eea651 --- /dev/null +++ b/lib/copy/plugins.ts @@ -0,0 +1,125 @@ +/** + * Plugins page copy — single source of truth for the plugin showcase. + */ + +export interface Plugin { + id: string; + name: string; + description: string; + skillCount: number; + capabilities: string[]; + installCommand: string; + repo: string; + /** Which tier of customer this targets */ + audience: string; +} + +export const pluginsCopy = { + title: "Agent Plugins for Music", + subtitle: + "Install a plugin. Your AI agent gets music industry superpowers. Works with Claude Code, Cowork, Codex, and Cursor.", + + plugins: [ + { + id: "research", + name: "Research", + description: + "Artist analytics, audience insights, competitive analysis, playlist intelligence, and trend detection. The foundation for any music business decision.", + skillCount: 7, + capabilities: [ + "Artist research & briefs", + "Audience demographics & cities", + "Competitive landscape", + "Playlist intelligence", + "Trend detection", + "Web intelligence", + "People outreach", + ], + installCommand: + "claude plugin install https://github.com/recoupable/recoup-research-plugin", + repo: "https://github.com/recoupable/recoup-research-plugin", + audience: "Labels, managers, distributors", + }, + { + id: "content", + name: "Content", + description: + "Generate release strategy content, social posts, and short-form video scripts. Your agent becomes your marketing team.", + skillCount: 3, + capabilities: [ + "Content creation workflows", + "Social post generation", + "Short-form video scripts", + ], + installCommand: + "claude plugin install https://github.com/recoupable/recoup-content-plugin", + repo: "https://github.com/recoupable/recoup-content-plugin", + audience: "Labels, managers, artists", + }, + { + id: "catalogs", + name: "Catalog Deals", + description: + "Turn a messy seller data room into a source-cited deal package. Royalty normalization, rights review, valuation analysis, financing underwriting, and IC memos — all agent-driven.", + skillCount: 17, + capabilities: [ + "Data room ingestion & normalization", + "Catalog valuation & analysis", + "Rights & ownership review", + "Royalty audit", + "Seller prep & cleanup", + "Financing underwriting", + "IC memo generation", + "Deal dashboard (HTML)", + ], + installCommand: + "claude plugin install https://github.com/recoupable/recoup-catalogs-plugin", + repo: "https://github.com/recoupable/recoup-catalogs-plugin", + audience: "Catalog acquirers, investors, lenders", + }, + { + id: "platform", + name: "Platform", + description: + "Onboarding and diagnostics. Your agent's starting point — validates credentials, discovers capabilities, and runs health checks.", + skillCount: 2, + capabilities: [ + "Guided onboarding flow", + "API key validation", + "Plugin discovery & recommendations", + "Health check & diagnostics", + ], + installCommand: + "claude plugin install https://github.com/recoupable/recoup-platform-plugin", + repo: "https://github.com/recoupable/recoup-platform-plugin", + audience: "Everyone — start here", + }, + ] satisfies Plugin[], + + compatibleWith: [ + "Claude Code", + "Claude Cowork", + "Codex", + "Cursor", + ], + + steps: [ + { + number: "1", + title: "Install", + description: "One command. Plugin loads into your AI tool of choice.", + }, + { + number: "2", + title: "Connect", + description: + "Set your Recoup API key. Get one free at developers.recoupable.com.", + }, + { + number: "3", + title: "Go", + description: + "Ask your agent anything about music. It now has the data and workflows to deliver.", + }, + ], +} as const; diff --git a/lib/nav.ts b/lib/nav.ts index 956cf3b..f26ab98 100644 --- a/lib/nav.ts +++ b/lib/nav.ts @@ -5,6 +5,7 @@ import { siteConfig } from "@/lib/config"; export const nav: readonly { label: string; href: string; external?: boolean }[] = [ + { label: "Plugins", href: "/plugins" }, { label: "Results", href: "/results" }, { label: "Pricing", href: "/pricing" }, { label: "Docs", href: siteConfig.docsUrl, external: true }, @@ -17,6 +18,7 @@ export const footerNav = { items: [ { label: "Platform", href: "/platform" }, { label: "Pricing", href: "/pricing" }, + { label: "Plugins", href: "/plugins" }, { label: "Docs", href: siteConfig.docsUrl, external: true }, ], },