feat: add general overview tutorial
- Add 6-slide overview tutorial covering TPMJS concepts - Slides: Welcome, What is TPMJS, Ecosystem, Architecture, Use Cases, Explore - Add OverviewSlideshow component and page route at /overview - Update main tutorial page with overview as first card
This commit is contained in:
parent
d132da9c20
commit
6ef33735a7
9 changed files with 637 additions and 2 deletions
16
apps/tutorial/src/app/overview/page.tsx
Normal file
16
apps/tutorial/src/app/overview/page.tsx
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import { OverviewSlideshow } from '@/components/OverviewSlideshow';
|
||||
import type { Metadata } from 'next';
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Overview | TPMJS Tutorials',
|
||||
description:
|
||||
'General overview of TPMJS - the tool registry for AI agents. Learn what TPMJS is, how it works, and who uses it.',
|
||||
};
|
||||
|
||||
export default function OverviewPage(): React.ReactElement {
|
||||
return (
|
||||
<main className="h-screen w-screen overflow-hidden">
|
||||
<OverviewSlideshow />
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
|
@ -4,6 +4,31 @@ import { motion } from 'framer-motion';
|
|||
import Link from 'next/link';
|
||||
|
||||
const tutorials = [
|
||||
{
|
||||
id: 'overview',
|
||||
title: 'General Overview',
|
||||
subtitle: 'Start Here',
|
||||
description: 'What is TPMJS? Learn about the registry, ecosystem, and architecture.',
|
||||
href: '/overview',
|
||||
gradient: 'from-emerald-500 to-teal-600',
|
||||
icon: (
|
||||
<svg
|
||||
className="w-8 h-8"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={1.5}
|
||||
d="M12 6.042A8.967 8.967 0 006 3.75c-1.052 0-2.062.18-3 .512v14.25A8.987 8.987 0 016 18c2.305 0 4.408.867 6 2.292m0-14.25a8.966 8.966 0 016-2.292c1.052 0 2.062.18 3 .512v14.25A8.987 8.987 0 0018 18a8.967 8.967 0 00-6 2.292m0-14.25v14.25"
|
||||
/>
|
||||
</svg>
|
||||
),
|
||||
features: ['What is TPMJS', 'Ecosystem', 'Architecture'],
|
||||
},
|
||||
{
|
||||
id: 'agents',
|
||||
title: 'For Agent Developers',
|
||||
|
|
@ -74,7 +99,7 @@ export default function TutorialHome(): React.ReactElement {
|
|||
/>
|
||||
|
||||
{/* Content */}
|
||||
<div className="relative z-10 max-w-4xl w-full">
|
||||
<div className="relative z-10 max-w-5xl w-full">
|
||||
{/* Header */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
|
|
@ -93,7 +118,7 @@ export default function TutorialHome(): React.ReactElement {
|
|||
</motion.div>
|
||||
|
||||
{/* Tutorial Cards */}
|
||||
<div className="grid md:grid-cols-2 gap-6">
|
||||
<div className="grid md:grid-cols-3 gap-6">
|
||||
{tutorials.map((tutorial, index) => (
|
||||
<motion.div
|
||||
key={tutorial.id}
|
||||
|
|
|
|||
85
apps/tutorial/src/components/OverviewSlideshow.tsx
Normal file
85
apps/tutorial/src/components/OverviewSlideshow.tsx
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
'use client';
|
||||
|
||||
import { useSlideshow } from '@/hooks/useSlideshow';
|
||||
import { AnimatePresence } from 'framer-motion';
|
||||
import Link from 'next/link';
|
||||
import { Slide } from './Slide';
|
||||
import { SlideNavigation } from './SlideNavigation';
|
||||
import { SlideProgress } from './SlideProgress';
|
||||
import { ArchitectureSlide } from './overview-slides/ArchitectureSlide';
|
||||
import { EcosystemSlide } from './overview-slides/EcosystemSlide';
|
||||
import { ExploreSlide } from './overview-slides/ExploreSlide';
|
||||
import { OverviewWelcomeSlide } from './overview-slides/OverviewWelcomeSlide';
|
||||
import { UseCasesSlide } from './overview-slides/UseCasesSlide';
|
||||
import { WhatIsTpmjsSlide } from './overview-slides/WhatIsTpmjsSlide';
|
||||
|
||||
const SLIDES = [
|
||||
{ id: 'welcome', Component: OverviewWelcomeSlide },
|
||||
{ id: 'what-is-tpmjs', Component: WhatIsTpmjsSlide },
|
||||
{ id: 'ecosystem', Component: EcosystemSlide },
|
||||
{ id: 'architecture', Component: ArchitectureSlide },
|
||||
{ id: 'use-cases', Component: UseCasesSlide },
|
||||
{ id: 'explore', Component: ExploreSlide },
|
||||
];
|
||||
|
||||
export function OverviewSlideshow(): React.ReactElement {
|
||||
const { currentSlide, totalSlides, next, prev, goTo, direction, isFirst, isLast } = useSlideshow({
|
||||
totalSlides: SLIDES.length,
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="relative h-full w-full bg-[#0a0a0f] overflow-hidden">
|
||||
{/* Background gradient */}
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-[#0a0a0f] via-[#0d1117] to-[#0a0a0f]" />
|
||||
|
||||
{/* Subtle grid pattern */}
|
||||
<div
|
||||
className="absolute inset-0 opacity-[0.03]"
|
||||
style={{
|
||||
backgroundImage: `
|
||||
linear-gradient(rgba(255,255,255,0.1) 1px, transparent 1px),
|
||||
linear-gradient(90deg, rgba(255,255,255,0.1) 1px, transparent 1px)
|
||||
`,
|
||||
backgroundSize: '50px 50px',
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Back button */}
|
||||
<Link
|
||||
href="/"
|
||||
className="fixed top-6 left-6 z-50 flex items-center gap-2 px-3 py-2 rounded-lg bg-white/5 border border-white/10 text-white/50 hover:text-white/80 hover:bg-white/10 transition-all text-sm"
|
||||
>
|
||||
<svg
|
||||
className="w-4 h-4"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
|
||||
</svg>
|
||||
Tutorials
|
||||
</Link>
|
||||
|
||||
{/* Slides */}
|
||||
<AnimatePresence mode="wait" custom={direction}>
|
||||
{SLIDES.map((slide, index) => (
|
||||
<Slide key={slide.id} isActive={index === currentSlide} direction={direction}>
|
||||
<slide.Component />
|
||||
</Slide>
|
||||
))}
|
||||
</AnimatePresence>
|
||||
|
||||
{/* Navigation */}
|
||||
<SlideNavigation onNext={next} onPrev={prev} isFirst={isFirst} isLast={isLast} />
|
||||
|
||||
{/* Progress */}
|
||||
<SlideProgress currentSlide={currentSlide} totalSlides={totalSlides} goTo={goTo} />
|
||||
|
||||
{/* Keyboard hint */}
|
||||
<div className="fixed bottom-8 right-8 z-50 text-white/30 text-xs font-mono">
|
||||
Use arrow keys or click to navigate
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
'use client';
|
||||
|
||||
import { motion } from 'framer-motion';
|
||||
|
||||
const components = [
|
||||
{
|
||||
name: 'npm Sync',
|
||||
description: 'Monitors npm changes feed every 2 minutes',
|
||||
detail: 'Catches new packages with tpmjs-tool keyword',
|
||||
icon: '🔄',
|
||||
},
|
||||
{
|
||||
name: 'Schema Extraction',
|
||||
description: 'Extracts Zod schemas to JSON Schema',
|
||||
detail: 'Supports AI SDK, Zod v3, and Zod v4',
|
||||
icon: '📋',
|
||||
},
|
||||
{
|
||||
name: 'Quality Scoring',
|
||||
description: 'Ranks tools by tier, downloads, and stars',
|
||||
detail: 'Rich metadata = higher visibility',
|
||||
icon: '⭐',
|
||||
},
|
||||
{
|
||||
name: 'Sandbox Executor',
|
||||
description: 'Runs tools in isolated Deno environment',
|
||||
detail: 'No installs, secure by default',
|
||||
icon: '🏖️',
|
||||
},
|
||||
];
|
||||
|
||||
export function ArchitectureSlide(): React.ReactElement {
|
||||
return (
|
||||
<div className="relative flex flex-col items-center justify-center h-full px-8 text-center">
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-cyan-900/10 via-transparent to-emerald-900/10 pointer-events-none" />
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.8 }}
|
||||
className="relative z-10 max-w-5xl w-full"
|
||||
>
|
||||
<h2 className="text-4xl md:text-5xl font-bold text-white mb-4">Under the Hood</h2>
|
||||
<p className="text-xl text-white/50 mb-10">Four core systems working together</p>
|
||||
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-4 max-w-4xl mx-auto">
|
||||
{components.map((component, index) => (
|
||||
<motion.div
|
||||
key={component.name}
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: 0.2 + index * 0.1 }}
|
||||
className="p-5 rounded-xl bg-white/5 border border-cyan-500/20 text-left"
|
||||
>
|
||||
<div className="text-3xl mb-3">{component.icon}</div>
|
||||
<div className="text-sm font-semibold text-cyan-400 mb-2">{component.name}</div>
|
||||
<div className="text-xs text-white/60 mb-2">{component.description}</div>
|
||||
<div className="text-xs text-white/30 font-mono">{component.detail}</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ delay: 0.8 }}
|
||||
className="mt-10 flex items-center justify-center gap-4 text-white/40 text-xs font-mono"
|
||||
>
|
||||
<span className="px-2 py-1 rounded bg-white/5">PostgreSQL</span>
|
||||
<span className="text-white/20">+</span>
|
||||
<span className="px-2 py-1 rounded bg-white/5">Prisma</span>
|
||||
<span className="text-white/20">+</span>
|
||||
<span className="px-2 py-1 rounded bg-white/5">Next.js</span>
|
||||
<span className="text-white/20">+</span>
|
||||
<span className="px-2 py-1 rounded bg-white/5">Deno</span>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
106
apps/tutorial/src/components/overview-slides/EcosystemSlide.tsx
Normal file
106
apps/tutorial/src/components/overview-slides/EcosystemSlide.tsx
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
'use client';
|
||||
|
||||
import { motion } from 'framer-motion';
|
||||
|
||||
const participants = [
|
||||
{
|
||||
role: 'Package Authors',
|
||||
action: 'Publish tools to npm with tpmjs-tool keyword',
|
||||
color: 'purple',
|
||||
},
|
||||
{
|
||||
role: 'TPMJS Registry',
|
||||
action: 'Syncs from npm, extracts schemas, scores quality',
|
||||
color: 'emerald',
|
||||
},
|
||||
{
|
||||
role: 'Agent Developers',
|
||||
action: 'Use meta-tools to search and execute at runtime',
|
||||
color: 'cyan',
|
||||
},
|
||||
];
|
||||
|
||||
export function EcosystemSlide(): React.ReactElement {
|
||||
return (
|
||||
<div className="relative flex flex-col items-center justify-center h-full px-8 text-center">
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-purple-900/10 via-emerald-900/5 to-cyan-900/10 pointer-events-none" />
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.8 }}
|
||||
className="relative z-10 max-w-4xl w-full"
|
||||
>
|
||||
<h2 className="text-4xl md:text-5xl font-bold text-white mb-4">The Ecosystem</h2>
|
||||
<p className="text-xl text-white/50 mb-12">Three participants, one registry</p>
|
||||
|
||||
{/* Flow diagram */}
|
||||
<div className="flex flex-col md:flex-row items-center justify-center gap-4 md:gap-8 max-w-4xl mx-auto">
|
||||
{participants.map((participant, index) => (
|
||||
<motion.div
|
||||
key={participant.role}
|
||||
initial={{ opacity: 0, x: -20 }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
transition={{ delay: 0.3 + index * 0.2 }}
|
||||
className="flex items-center gap-4"
|
||||
>
|
||||
<div
|
||||
className={`p-6 rounded-xl bg-white/5 border text-left min-w-[200px] ${
|
||||
participant.color === 'purple'
|
||||
? 'border-purple-500/30'
|
||||
: participant.color === 'emerald'
|
||||
? 'border-emerald-500/30'
|
||||
: 'border-cyan-500/30'
|
||||
}`}
|
||||
>
|
||||
<div
|
||||
className={`text-sm font-semibold mb-2 ${
|
||||
participant.color === 'purple'
|
||||
? 'text-purple-400'
|
||||
: participant.color === 'emerald'
|
||||
? 'text-emerald-400'
|
||||
: 'text-cyan-400'
|
||||
}`}
|
||||
>
|
||||
{participant.role}
|
||||
</div>
|
||||
<div className="text-xs text-white/50">{participant.action}</div>
|
||||
</div>
|
||||
|
||||
{/* Arrow between items */}
|
||||
{index < participants.length - 1 && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, scale: 0 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
transition={{ delay: 0.6 + index * 0.2 }}
|
||||
className="text-white/30 hidden md:block"
|
||||
>
|
||||
<svg className="w-6 h-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M9 5l7 7-7 7"
|
||||
/>
|
||||
</svg>
|
||||
</motion.div>
|
||||
)}
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ delay: 1.2 }}
|
||||
className="mt-12 p-4 rounded-lg bg-white/5 border border-white/10 max-w-md mx-auto"
|
||||
>
|
||||
<p className="text-sm text-white/60">
|
||||
<span className="text-emerald-400 font-semibold">200+</span> tools from{' '}
|
||||
<span className="text-purple-400 font-semibold">50+</span> packages available today
|
||||
</p>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
'use client';
|
||||
|
||||
import { motion } from 'framer-motion';
|
||||
|
||||
const resources = [
|
||||
{
|
||||
title: 'Browse Tools',
|
||||
description: 'Explore 200+ tools in the registry',
|
||||
href: 'https://tpmjs.com',
|
||||
icon: '🔍',
|
||||
},
|
||||
{
|
||||
title: 'For Agents',
|
||||
description: 'Learn to use search and execute',
|
||||
href: '/agents',
|
||||
icon: '🤖',
|
||||
internal: true,
|
||||
},
|
||||
{
|
||||
title: 'For Authors',
|
||||
description: 'Publish your tools to the registry',
|
||||
href: '/authors',
|
||||
icon: '📦',
|
||||
internal: true,
|
||||
},
|
||||
{
|
||||
title: 'GitHub',
|
||||
description: 'View the source code',
|
||||
href: 'https://github.com/tpmjs/tpmjs',
|
||||
icon: '💻',
|
||||
},
|
||||
];
|
||||
|
||||
export function ExploreSlide(): React.ReactElement {
|
||||
return (
|
||||
<div className="relative flex flex-col items-center justify-center h-full px-8 text-center">
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-emerald-900/20 via-transparent to-cyan-900/20 pointer-events-none" />
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.8 }}
|
||||
className="relative z-10 max-w-4xl w-full"
|
||||
>
|
||||
<h2 className="text-4xl md:text-5xl font-bold text-white mb-4">Start Exploring</h2>
|
||||
<p className="text-xl text-white/50 mb-12">Choose your next step</p>
|
||||
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-4 max-w-3xl mx-auto">
|
||||
{resources.map((resource, index) => (
|
||||
<motion.a
|
||||
key={resource.title}
|
||||
href={resource.href}
|
||||
target={resource.internal ? undefined : '_blank'}
|
||||
rel={resource.internal ? undefined : 'noopener noreferrer'}
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: 0.3 + index * 0.1 }}
|
||||
className="p-5 rounded-xl bg-white/5 border border-emerald-500/20 text-left hover:bg-white/10 hover:border-emerald-500/40 transition-all group cursor-pointer"
|
||||
>
|
||||
<div className="text-3xl mb-3 group-hover:scale-110 transition-transform">
|
||||
{resource.icon}
|
||||
</div>
|
||||
<div className="text-sm font-semibold text-emerald-400 mb-1">{resource.title}</div>
|
||||
<div className="text-xs text-white/50">{resource.description}</div>
|
||||
</motion.a>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ delay: 0.8 }}
|
||||
className="mt-12 p-6 rounded-xl bg-gradient-to-r from-emerald-500/10 to-cyan-500/10 border border-emerald-500/20 max-w-md mx-auto"
|
||||
>
|
||||
<p className="text-white/70 text-sm mb-2">Ready to try it?</p>
|
||||
<code className="text-emerald-400 font-mono text-sm">
|
||||
npm install @tpmjs/search-registry
|
||||
</code>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ delay: 1 }}
|
||||
className="mt-8 text-white/30 text-xs font-mono"
|
||||
>
|
||||
tpmjs.com — The tool registry for AI agents
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
'use client';
|
||||
|
||||
import { motion } from 'framer-motion';
|
||||
|
||||
export function OverviewWelcomeSlide(): React.ReactElement {
|
||||
return (
|
||||
<div className="relative flex flex-col items-center justify-center h-full px-8 text-center overflow-hidden">
|
||||
{/* Gradient background */}
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-emerald-900/20 via-transparent to-cyan-900/20 pointer-events-none" />
|
||||
|
||||
{/* Main content */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.8, ease: 'easeOut' }}
|
||||
className="relative z-10 max-w-4xl"
|
||||
>
|
||||
<motion.div
|
||||
initial={{ opacity: 0, scale: 0.9 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
transition={{ duration: 0.6, delay: 0.2 }}
|
||||
className="mb-6"
|
||||
>
|
||||
<span className="text-sm font-mono text-emerald-400/60 tracking-widest uppercase">
|
||||
General Overview
|
||||
</span>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0, scale: 0.9 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
transition={{ duration: 0.6, delay: 0.3 }}
|
||||
className="mb-8"
|
||||
>
|
||||
<span className="text-6xl md:text-7xl font-bold bg-gradient-to-r from-emerald-400 to-cyan-400 bg-clip-text text-transparent">
|
||||
TPMJS
|
||||
</span>
|
||||
</motion.div>
|
||||
|
||||
<motion.h1
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ duration: 0.6, delay: 0.5 }}
|
||||
className="text-2xl md:text-3xl font-medium text-white/90 mb-6"
|
||||
>
|
||||
The Tool Package Manager for AI
|
||||
</motion.h1>
|
||||
|
||||
<motion.p
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ duration: 0.6, delay: 0.7 }}
|
||||
className="text-lg text-white/50 font-mono max-w-xl mx-auto"
|
||||
>
|
||||
An open registry of AI SDK tools that agents can discover and execute at runtime
|
||||
</motion.p>
|
||||
</motion.div>
|
||||
|
||||
{/* Press to continue */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ duration: 0.8, delay: 1.2 }}
|
||||
className="absolute bottom-12 flex flex-col items-center"
|
||||
>
|
||||
<motion.div
|
||||
animate={{ y: [0, 8, 0] }}
|
||||
transition={{ duration: 1.5, repeat: Number.POSITIVE_INFINITY, ease: 'easeInOut' }}
|
||||
className="text-white/40"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
className="w-6 h-6"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={1.5}
|
||||
d="M19 9l-7 7-7-7"
|
||||
/>
|
||||
</svg>
|
||||
</motion.div>
|
||||
<span className="mt-2 text-sm text-white/30 font-mono">Press any key</span>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
'use client';
|
||||
|
||||
import { motion } from 'framer-motion';
|
||||
|
||||
const useCases = [
|
||||
{
|
||||
persona: 'AI Agent Developers',
|
||||
useCase: 'Give agents dynamic capabilities without bundling tools',
|
||||
example: '"Find me a weather tool" → Agent discovers and uses it',
|
||||
gradient: 'from-cyan-500 to-blue-500',
|
||||
},
|
||||
{
|
||||
persona: 'Tool Authors',
|
||||
useCase: 'Get your AI SDK tools discovered by agents worldwide',
|
||||
example: 'npm publish with tpmjs-tool keyword → Indexed in minutes',
|
||||
gradient: 'from-purple-500 to-pink-500',
|
||||
},
|
||||
{
|
||||
persona: 'Platform Builders',
|
||||
useCase: 'Build agent platforms with extensible tool ecosystems',
|
||||
example: 'Users bring their own tools, you provide the runtime',
|
||||
gradient: 'from-emerald-500 to-teal-500',
|
||||
},
|
||||
];
|
||||
|
||||
export function UseCasesSlide(): React.ReactElement {
|
||||
return (
|
||||
<div className="relative flex flex-col items-center justify-center h-full px-8 text-center">
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-purple-900/10 via-transparent to-cyan-900/10 pointer-events-none" />
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.8 }}
|
||||
className="relative z-10 max-w-4xl w-full"
|
||||
>
|
||||
<h2 className="text-4xl md:text-5xl font-bold text-white mb-4">Who Uses TPMJS?</h2>
|
||||
<p className="text-xl text-white/50 mb-12">Three audiences, shared ecosystem</p>
|
||||
|
||||
<div className="space-y-4 max-w-3xl mx-auto">
|
||||
{useCases.map((item, index) => (
|
||||
<motion.div
|
||||
key={item.persona}
|
||||
initial={{ opacity: 0, x: -30 }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
transition={{ delay: 0.3 + index * 0.15 }}
|
||||
className="p-6 rounded-xl bg-white/5 border border-white/10 text-left flex flex-col md:flex-row md:items-center gap-4"
|
||||
>
|
||||
<div className="md:w-1/3">
|
||||
<div
|
||||
className={`text-lg font-semibold bg-gradient-to-r ${item.gradient} bg-clip-text text-transparent`}
|
||||
>
|
||||
{item.persona}
|
||||
</div>
|
||||
</div>
|
||||
<div className="md:w-2/3">
|
||||
<div className="text-sm text-white/70 mb-1">{item.useCase}</div>
|
||||
<div className="text-xs text-white/40 font-mono">{item.example}</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ delay: 1 }}
|
||||
className="mt-10 text-white/40 text-sm"
|
||||
>
|
||||
All built on standard npm packages and the AI SDK specification
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
'use client';
|
||||
|
||||
import { motion } from 'framer-motion';
|
||||
|
||||
const concepts = [
|
||||
{
|
||||
title: 'A Registry',
|
||||
description: 'A curated database of AI SDK-compatible tools published to npm',
|
||||
icon: '📦',
|
||||
},
|
||||
{
|
||||
title: 'A Discovery API',
|
||||
description: 'Agents search for tools by query, category, or context at runtime',
|
||||
icon: '🔍',
|
||||
},
|
||||
{
|
||||
title: 'A Sandbox Executor',
|
||||
description: 'Run any tool from the registry securely without installing it',
|
||||
icon: '⚡',
|
||||
},
|
||||
];
|
||||
|
||||
export function WhatIsTpmjsSlide(): React.ReactElement {
|
||||
return (
|
||||
<div className="relative flex flex-col items-center justify-center h-full px-8 text-center">
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-emerald-900/10 via-transparent to-cyan-900/10 pointer-events-none" />
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.8 }}
|
||||
className="relative z-10 max-w-4xl w-full"
|
||||
>
|
||||
<h2 className="text-4xl md:text-5xl font-bold text-white mb-4">What is TPMJS?</h2>
|
||||
<p className="text-xl text-white/50 mb-12 max-w-2xl mx-auto">
|
||||
Think of it as npm for AI agent tools — but with runtime discovery and execution
|
||||
</p>
|
||||
|
||||
<div className="grid md:grid-cols-3 gap-6 max-w-4xl mx-auto">
|
||||
{concepts.map((concept, index) => (
|
||||
<motion.div
|
||||
key={concept.title}
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: 0.3 + index * 0.15 }}
|
||||
className="p-6 rounded-xl bg-white/5 border border-emerald-500/20 text-left"
|
||||
>
|
||||
<div className="text-4xl mb-4">{concept.icon}</div>
|
||||
<div className="text-lg font-semibold text-emerald-400 mb-3">{concept.title}</div>
|
||||
<div className="text-sm text-white/50">{concept.description}</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ delay: 0.9 }}
|
||||
className="mt-10 text-white/40 text-sm font-mono"
|
||||
>
|
||||
Built on the Vercel AI SDK tool specification
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue