diff --git a/apps/tutorial/src/app/agent-example/page.tsx b/apps/tutorial/src/app/agent-example/page.tsx new file mode 100644 index 0000000..112f1ff --- /dev/null +++ b/apps/tutorial/src/app/agent-example/page.tsx @@ -0,0 +1,16 @@ +import { AgentExampleSlideshow } from '@/components/AgentExampleSlideshow'; +import type { Metadata } from 'next'; + +export const metadata: Metadata = { + title: 'Real-World Agent Example | TPMJS Tutorials', + description: + 'Build a complete AI agent that discovers and uses tools dynamically from the TPMJS registry. Working code examples included.', +}; + +export default function AgentExamplePage(): React.ReactElement { + return ( +
+ +
+ ); +} diff --git a/apps/tutorial/src/app/first-tool/page.tsx b/apps/tutorial/src/app/first-tool/page.tsx new file mode 100644 index 0000000..5f6a007 --- /dev/null +++ b/apps/tutorial/src/app/first-tool/page.tsx @@ -0,0 +1,16 @@ +import { FirstToolSlideshow } from '@/components/FirstToolSlideshow'; +import type { Metadata } from 'next'; + +export const metadata: Metadata = { + title: 'Build Your First Tool | TPMJS Tutorials', + description: + 'Step-by-step guide to creating your first AI SDK tool for the TPMJS registry. From npm init to published tool in 10 minutes.', +}; + +export default function FirstToolPage(): React.ReactElement { + return ( +
+ +
+ ); +} diff --git a/apps/tutorial/src/app/page.tsx b/apps/tutorial/src/app/page.tsx index 7342375..b376992 100644 --- a/apps/tutorial/src/app/page.tsx +++ b/apps/tutorial/src/app/page.tsx @@ -80,6 +80,81 @@ const tutorials = [ ), features: ['tpmjs keyword', 'Schema extraction', 'Quality scoring'], }, + { + id: 'first-tool', + title: 'Build Your First Tool', + subtitle: 'Step-by-Step', + description: 'Create an AI SDK tool from scratch and publish it to the registry in 10 minutes.', + href: '/first-tool', + gradient: 'from-orange-500 to-amber-600', + icon: ( + + ), + features: ['npm init', 'Zod schema', 'npm publish'], + }, + { + id: 'agent-example', + title: 'Real-World Agent', + subtitle: 'Working Example', + description: 'Build a complete agent that discovers and uses tools dynamically.', + href: '/agent-example', + gradient: 'from-rose-500 to-pink-600', + icon: ( + + ), + features: ['generateText', 'maxSteps', 'Meta-tools'], + }, + { + id: 'playground', + title: 'Interactive Playground', + subtitle: 'Try Before Install', + description: 'Test any tool directly in your browser without installation.', + href: '/playground', + gradient: 'from-sky-500 to-blue-600', + icon: ( + + ), + features: ['Live execution', 'Schema forms', 'JSON output'], + }, ]; export default function TutorialHome(): React.ReactElement { @@ -99,7 +174,7 @@ export default function TutorialHome(): React.ReactElement { /> {/* Content */} -
+
{/* Header */} + + + ); +} diff --git a/apps/tutorial/src/components/AgentExampleSlideshow.tsx b/apps/tutorial/src/components/AgentExampleSlideshow.tsx new file mode 100644 index 0000000..9a38f3c --- /dev/null +++ b/apps/tutorial/src/components/AgentExampleSlideshow.tsx @@ -0,0 +1,77 @@ +'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 { AgentCodeSlide } from './agent-example-slides/AgentCodeSlide'; +import { AgentExampleNextStepsSlide } from './agent-example-slides/AgentExampleNextStepsSlide'; +import { AgentExampleWelcomeSlide } from './agent-example-slides/AgentExampleWelcomeSlide'; +import { ExecutionFlowSlide } from './agent-example-slides/ExecutionFlowSlide'; +import { SetupCodeSlide } from './agent-example-slides/SetupCodeSlide'; +import { TheGoalSlide } from './agent-example-slides/TheGoalSlide'; + +const SLIDES = [ + { id: 'welcome', Component: AgentExampleWelcomeSlide }, + { id: 'the-goal', Component: TheGoalSlide }, + { id: 'setup', Component: SetupCodeSlide }, + { id: 'agent-code', Component: AgentCodeSlide }, + { id: 'execution-flow', Component: ExecutionFlowSlide }, + { id: 'next-steps', Component: AgentExampleNextStepsSlide }, +]; + +export function AgentExampleSlideshow(): React.ReactElement { + const { currentSlide, totalSlides, next, prev, goTo, direction, isFirst, isLast } = useSlideshow({ + totalSlides: SLIDES.length, + }); + + return ( +
+
+ +
+ + + + Tutorials + + + + {SLIDES.map((slide, index) => ( + + + + ))} + + + + + +
+ Use arrow keys or click to navigate +
+
+ ); +} diff --git a/apps/tutorial/src/components/FirstToolSlideshow.tsx b/apps/tutorial/src/components/FirstToolSlideshow.tsx new file mode 100644 index 0000000..7be911a --- /dev/null +++ b/apps/tutorial/src/components/FirstToolSlideshow.tsx @@ -0,0 +1,77 @@ +'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 { FirstToolNextStepsSlide } from './first-tool-slides/FirstToolNextStepsSlide'; +import { FirstToolWelcomeSlide } from './first-tool-slides/FirstToolWelcomeSlide'; +import { PackageJsonSlide } from './first-tool-slides/PackageJsonSlide'; +import { ProjectSetupSlide } from './first-tool-slides/ProjectSetupSlide'; +import { PublishSlide } from './first-tool-slides/PublishSlide'; +import { WriteToolSlide } from './first-tool-slides/WriteToolSlide'; + +const SLIDES = [ + { id: 'welcome', Component: FirstToolWelcomeSlide }, + { id: 'project-setup', Component: ProjectSetupSlide }, + { id: 'write-tool', Component: WriteToolSlide }, + { id: 'package-json', Component: PackageJsonSlide }, + { id: 'publish', Component: PublishSlide }, + { id: 'next-steps', Component: FirstToolNextStepsSlide }, +]; + +export function FirstToolSlideshow(): React.ReactElement { + const { currentSlide, totalSlides, next, prev, goTo, direction, isFirst, isLast } = useSlideshow({ + totalSlides: SLIDES.length, + }); + + return ( +
+
+ +
+ + + + Tutorials + + + + {SLIDES.map((slide, index) => ( + + + + ))} + + + + + +
+ Use arrow keys or click to navigate +
+
+ ); +} diff --git a/apps/tutorial/src/components/PlaygroundSlideshow.tsx b/apps/tutorial/src/components/PlaygroundSlideshow.tsx new file mode 100644 index 0000000..3489e6f --- /dev/null +++ b/apps/tutorial/src/components/PlaygroundSlideshow.tsx @@ -0,0 +1,77 @@ +'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 { FillParametersSlide } from './playground-slides/FillParametersSlide'; +import { FindToolSlide } from './playground-slides/FindToolSlide'; +import { OpenPlaygroundSlide } from './playground-slides/OpenPlaygroundSlide'; +import { PlaygroundNextStepsSlide } from './playground-slides/PlaygroundNextStepsSlide'; +import { PlaygroundWelcomeSlide } from './playground-slides/PlaygroundWelcomeSlide'; +import { SeeResultsSlide } from './playground-slides/SeeResultsSlide'; + +const SLIDES = [ + { id: 'welcome', Component: PlaygroundWelcomeSlide }, + { id: 'find-tool', Component: FindToolSlide }, + { id: 'open-playground', Component: OpenPlaygroundSlide }, + { id: 'fill-parameters', Component: FillParametersSlide }, + { id: 'see-results', Component: SeeResultsSlide }, + { id: 'next-steps', Component: PlaygroundNextStepsSlide }, +]; + +export function PlaygroundSlideshow(): React.ReactElement { + const { currentSlide, totalSlides, next, prev, goTo, direction, isFirst, isLast } = useSlideshow({ + totalSlides: SLIDES.length, + }); + + return ( +
+
+ +
+ + + + Tutorials + + + + {SLIDES.map((slide, index) => ( + + + + ))} + + + + + +
+ Use arrow keys or click to navigate +
+
+ ); +} diff --git a/apps/tutorial/src/components/agent-example-slides/AgentCodeSlide.tsx b/apps/tutorial/src/components/agent-example-slides/AgentCodeSlide.tsx new file mode 100644 index 0000000..7870769 --- /dev/null +++ b/apps/tutorial/src/components/agent-example-slides/AgentCodeSlide.tsx @@ -0,0 +1,104 @@ +'use client'; + +import { motion } from 'framer-motion'; + +export function AgentCodeSlide(): React.ReactElement { + return ( +
+
+ + +
Step 2
+

The Agent Loop

+

Pass meta-tools to generateText with maxSteps

+ + +
agent.ts
+
+            
+              const
+               result = 
+              await
+               generateText
+              {'({'}
+              {'\n'}
+              {'  '}
+              model
+              : 
+              openai
+              (
+              'gpt-4o'
+              ),
+              {'\n'}
+              {'  '}
+              tools
+              {': {'}
+              {'\n'}
+              {'    '}
+              search
+              : 
+              searchTpmjsToolsTool
+              ,
+              {'\n'}
+              {'    '}
+              execute
+              : 
+              registryExecuteTool
+              ,
+              {'\n'}
+              {'  },'}
+              {'\n'}
+              {'  '}
+              maxSteps
+              : 
+              10
+              ,
+              {' // Allow multiple tool calls'}
+              {'\n'}
+              {'  '}
+              system
+              : 
+              `You are an assistant that can find and use
+              {'\n'}
+              
+                {' '}
+                tools from the TPMJS registry. First search for
+              
+              {'\n'}
+               relevant tools, then execute them.`
+              ,
+              {'\n'}
+              {'  '}
+              prompt
+              : userRequest,
+              {'\n'}
+              {'});'}
+            
+          
+
+ + +

+ Key: maxSteps allows the agent to search, then + execute, then reason about results +

+
+
+
+ ); +} diff --git a/apps/tutorial/src/components/agent-example-slides/AgentExampleNextStepsSlide.tsx b/apps/tutorial/src/components/agent-example-slides/AgentExampleNextStepsSlide.tsx new file mode 100644 index 0000000..82f10e9 --- /dev/null +++ b/apps/tutorial/src/components/agent-example-slides/AgentExampleNextStepsSlide.tsx @@ -0,0 +1,80 @@ +'use client'; + +import { motion } from 'framer-motion'; + +export function AgentExampleNextStepsSlide(): React.ReactElement { + return ( +
+
+ + +

Try It Yourself

+

Complete working example

+ + +
Clone & Run
+
+            
+              git clone
+               github.com/tpmjs/agent-example
+              {'\n'}
+              cd
+               agent-example
+              {'\n'}
+              npm
+               install
+              {'\n'}
+              npm
+               run dev
+            
+          
+
+ + + +
๐Ÿ”
+
Browse Registry
+
See all available tools
+
+ +
๐Ÿ“š
+
Agent Docs
+
Deep dive into meta-tools
+
+
+ + + Your agent can now use 200+ tools without installing any of them + +
+
+ ); +} diff --git a/apps/tutorial/src/components/agent-example-slides/AgentExampleWelcomeSlide.tsx b/apps/tutorial/src/components/agent-example-slides/AgentExampleWelcomeSlide.tsx new file mode 100644 index 0000000..7f1b525 --- /dev/null +++ b/apps/tutorial/src/components/agent-example-slides/AgentExampleWelcomeSlide.tsx @@ -0,0 +1,87 @@ +'use client'; + +import { motion } from 'framer-motion'; + +export function AgentExampleWelcomeSlide(): React.ReactElement { + return ( +
+
+ + + + + Practical Example + + + + + + Real-World Agent + + + + + Build an agent that discovers and uses tools dynamically + + + + A complete working example with search, execute, and reasoning + + + + + + + + Press any key + +
+ ); +} diff --git a/apps/tutorial/src/components/agent-example-slides/ExecutionFlowSlide.tsx b/apps/tutorial/src/components/agent-example-slides/ExecutionFlowSlide.tsx new file mode 100644 index 0000000..04f57d1 --- /dev/null +++ b/apps/tutorial/src/components/agent-example-slides/ExecutionFlowSlide.tsx @@ -0,0 +1,95 @@ +'use client'; + +import { motion } from 'framer-motion'; + +const steps = [ + { + step: '1', + action: 'Agent receives request', + detail: '"Format this markdown..."', + color: 'rose', + }, + { + step: '2', + action: 'Calls searchTpmjsToolsTool', + detail: 'query: "markdown formatter"', + color: 'pink', + }, + { + step: '3', + action: 'Receives tool list', + detail: '[markdownFormat, mdToHtml, ...]', + color: 'purple', + }, + { + step: '4', + action: 'Calls registryExecuteTool', + detail: 'toolId: "markdownFormat", args: {...}', + color: 'violet', + }, + { + step: '5', + action: 'Returns result to user', + detail: 'Formatted blog post', + color: 'indigo', + }, +]; + +export function ExecutionFlowSlide(): React.ReactElement { + return ( +
+
+ + +

Execution Flow

+

What happens when the agent runs

+ +
+ {steps.map((step, index) => ( + +
+ {step.step} +
+
+
{step.action}
+
{step.detail}
+
+
+ ))} +
+ + + All tool execution happens in a secure sandbox + +
+
+ ); +} diff --git a/apps/tutorial/src/components/agent-example-slides/SetupCodeSlide.tsx b/apps/tutorial/src/components/agent-example-slides/SetupCodeSlide.tsx new file mode 100644 index 0000000..7a8362e --- /dev/null +++ b/apps/tutorial/src/components/agent-example-slides/SetupCodeSlide.tsx @@ -0,0 +1,81 @@ +'use client'; + +import { motion } from 'framer-motion'; + +export function SetupCodeSlide(): React.ReactElement { + return ( +
+
+ + +
Step 1
+

Install & Setup

+

Add the TPMJS meta-tools to your project

+ + +
Terminal
+
+            
+              npm
+              
+                {' '}
+                install @tpmjs/search-registry @tpmjs/registry-execute
+              
+            
+          
+
+ + +
agent.ts
+
+            
+              import
+              {' { searchTpmjsToolsTool } '}
+              from
+              {'\n'}
+               '@tpmjs/search-registry'
+              ;
+              {'\n'}
+              import
+              {' { registryExecuteTool } '}
+              from
+              {'\n'}
+               '@tpmjs/registry-execute'
+              ;
+              {'\n'}
+              import
+              {' { generateText } '}
+              from
+               'ai'
+              ;
+            
+          
+
+ + + Two tools that give your agent access to the entire registry + +
+
+ ); +} diff --git a/apps/tutorial/src/components/agent-example-slides/TheGoalSlide.tsx b/apps/tutorial/src/components/agent-example-slides/TheGoalSlide.tsx new file mode 100644 index 0000000..1f7bd23 --- /dev/null +++ b/apps/tutorial/src/components/agent-example-slides/TheGoalSlide.tsx @@ -0,0 +1,77 @@ +'use client'; + +import { motion } from 'framer-motion'; + +export function TheGoalSlide(): React.ReactElement { + return ( +
+
+ + +

The Goal

+

+ An agent that can handle any request by finding the right tools +

+ + +
User Request
+

+ "Convert this markdown to a formatted blog post and generate a summary" +

+
+ + + + + + +
+
1. Search
+
Find markdown tools
+
+
+
2. Execute
+
Format the content
+
+
+
3. Return
+
Give result to user
+
+
+
+
+ ); +} diff --git a/apps/tutorial/src/components/first-tool-slides/FirstToolNextStepsSlide.tsx b/apps/tutorial/src/components/first-tool-slides/FirstToolNextStepsSlide.tsx new file mode 100644 index 0000000..ee779f1 --- /dev/null +++ b/apps/tutorial/src/components/first-tool-slides/FirstToolNextStepsSlide.tsx @@ -0,0 +1,71 @@ +'use client'; + +import { motion } from 'framer-motion'; + +const nextSteps = [ + { + title: 'Add Rich Metadata', + description: 'Include tpmjs field in package.json for better quality scores', + href: '/authors', + icon: '๐Ÿ“‹', + }, + { + title: 'Test in Playground', + description: 'Try your tool at tpmjs.com/tool/your-package/yourTool', + href: '/playground', + icon: '๐ŸŽฎ', + }, + { + title: 'View on Registry', + description: 'See how agents discover your tool', + href: 'https://tpmjs.com', + icon: '๐Ÿ”', + }, +]; + +export function FirstToolNextStepsSlide(): React.ReactElement { + return ( +
+
+ + +

You're Published!

+

Your tool is now discoverable by AI agents

+ +
+ {nextSteps.map((step, index) => ( + +
+ {step.icon} +
+
{step.title}
+
{step.description}
+
+ ))} +
+ + +

Complete code example:

+ github.com/tpmjs/example-tool +
+
+
+ ); +} diff --git a/apps/tutorial/src/components/first-tool-slides/FirstToolWelcomeSlide.tsx b/apps/tutorial/src/components/first-tool-slides/FirstToolWelcomeSlide.tsx new file mode 100644 index 0000000..73b4f4d --- /dev/null +++ b/apps/tutorial/src/components/first-tool-slides/FirstToolWelcomeSlide.tsx @@ -0,0 +1,87 @@ +'use client'; + +import { motion } from 'framer-motion'; + +export function FirstToolWelcomeSlide(): React.ReactElement { + return ( +
+
+ + + + + Step-by-Step Guide + + + + + + Build Your First Tool + + + + + From npm init to published tool in 10 minutes + + + + Create an AI SDK tool that agents can discover and execute + + + + + + + + Press any key + +
+ ); +} diff --git a/apps/tutorial/src/components/first-tool-slides/PackageJsonSlide.tsx b/apps/tutorial/src/components/first-tool-slides/PackageJsonSlide.tsx new file mode 100644 index 0000000..38af26b --- /dev/null +++ b/apps/tutorial/src/components/first-tool-slides/PackageJsonSlide.tsx @@ -0,0 +1,96 @@ +'use client'; + +import { motion } from 'framer-motion'; + +export function PackageJsonSlide(): React.ReactElement { + return ( +
+
+ + +
Step 3
+

Configure package.json

+

Add the tpmjs-tool keyword for discovery

+ + +
package.json
+
+            
+              {'{'}
+              {'\n'}
+              {'  '}
+              "name"
+              : 
+              "my-ai-tool"
+              ,
+              {'\n'}
+              {'  '}
+              "version"
+              : 
+              "1.0.0"
+              ,
+              {'\n'}
+              {'  '}
+              "keywords"
+              : [
+              {'\n'}
+              {'    '}
+              "tpmjs-tool"
+              {' โ† Required for discovery'}
+              {'\n'}
+              {'  ],'}]
+              {'\n'}
+              {'  '}
+              "main"
+              : 
+              "dist/index.js"
+              ,
+              {'\n'}
+              {'  '}
+              "types"
+              : 
+              "dist/index.d.ts"
+              ,
+              {'\n'}
+              {'  '}
+              "exports"
+              {': {'}
+              {'\n'}
+              {'    '}
+              "."
+              : 
+              "./dist/index.js"
+              {'\n'}
+              {'  }'}
+              {'\n'}
+              {'}'}
+            
+          
+
+ + +

+ Key: The{' '} + tpmjs-tool keyword triggers + automatic indexing +

+
+
+
+ ); +} diff --git a/apps/tutorial/src/components/first-tool-slides/ProjectSetupSlide.tsx b/apps/tutorial/src/components/first-tool-slides/ProjectSetupSlide.tsx new file mode 100644 index 0000000..e836ec5 --- /dev/null +++ b/apps/tutorial/src/components/first-tool-slides/ProjectSetupSlide.tsx @@ -0,0 +1,68 @@ +'use client'; + +import { motion } from 'framer-motion'; + +export function ProjectSetupSlide(): React.ReactElement { + return ( +
+
+ + +
Step 1
+

Project Setup

+

Create a new npm package

+ + +
Terminal
+
+            
+              # Create directory
+              {'\n'}
+              mkdir
+               my-ai-tool
+              {'\n'}
+              cd
+               my-ai-tool
+              {'\n\n'}
+              # Initialize package
+              {'\n'}
+              npm
+               init -y
+              {'\n\n'}
+              # Install dependencies
+              {'\n'}
+              npm
+               install ai zod
+            
+          
+
+ + + + ai + + + + + zod + + = AI SDK tools + +
+
+ ); +} diff --git a/apps/tutorial/src/components/first-tool-slides/PublishSlide.tsx b/apps/tutorial/src/components/first-tool-slides/PublishSlide.tsx new file mode 100644 index 0000000..f4c7d46 --- /dev/null +++ b/apps/tutorial/src/components/first-tool-slides/PublishSlide.tsx @@ -0,0 +1,73 @@ +'use client'; + +import { motion } from 'framer-motion'; + +export function PublishSlide(): React.ReactElement { + return ( +
+
+ + +
Step 4
+

Publish to npm

+

Build and publish your tool

+ + +
Terminal
+
+            
+              # Build TypeScript
+              {'\n'}
+              npm
+               run build
+              {'\n\n'}
+              # Publish to npm
+              {'\n'}
+              npm
+               publish
+            
+          
+
+ + +
+
๐Ÿ“ฆ
+
Published to npm
+
+
+
๐Ÿ”„
+
Synced in ~2 min
+
+
+
โœจ
+
Live on tpmjs.com
+
+
+ + + TPMJS syncs from npm's changes feed every 2 minutes + +
+
+ ); +} diff --git a/apps/tutorial/src/components/first-tool-slides/WriteToolSlide.tsx b/apps/tutorial/src/components/first-tool-slides/WriteToolSlide.tsx new file mode 100644 index 0000000..0b5be13 --- /dev/null +++ b/apps/tutorial/src/components/first-tool-slides/WriteToolSlide.tsx @@ -0,0 +1,107 @@ +'use client'; + +import { motion } from 'framer-motion'; + +export function WriteToolSlide(): React.ReactElement { + return ( +
+
+ + +
Step 2
+

Write Your Tool

+

+ Define schema, description, and execute function +

+ + +
src/index.ts
+
+            
+              import
+              {' { tool } '}
+              from
+              {" 'ai'"}
+              ;
+              {'\n'}
+              import
+              {' { z } '}
+              from
+              {" 'zod'"}
+              ;
+              {'\n\n'}
+              export const
+               greetingTool
+               = 
+              tool
+              {'({'}
+              {'\n'}
+              {'  '}
+              description
+              : 
+              'Generate a greeting'
+              ,
+              {'\n'}
+              {'  '}
+              parameters
+              : z.
+              object
+              {'({'}
+              {'\n'}
+              {'    '}
+              name
+              : z.
+              string
+              ().
+              describe
+              (
+              'Name'
+              ),
+              {'\n'}
+              {'  }'}),
+              {'\n'}
+              {'  '}
+              execute
+              : 
+              async
+              {' ({ name }) => {'}
+              {'\n'}
+              {'    '}
+              return
+               
+              `Hello, 
+              {'${'}
+              name
+              {'}'}
+              !`
+              ;
+              {'\n'}
+              {'  },'}
+              {'\n'}
+              {'});'}
+            
+          
+
+ + + The AI SDK tool() wrapper makes it compatible with generateText() + +
+
+ ); +} diff --git a/apps/tutorial/src/components/playground-slides/FillParametersSlide.tsx b/apps/tutorial/src/components/playground-slides/FillParametersSlide.tsx new file mode 100644 index 0000000..59aeef2 --- /dev/null +++ b/apps/tutorial/src/components/playground-slides/FillParametersSlide.tsx @@ -0,0 +1,80 @@ +'use client'; + +import { motion } from 'framer-motion'; + +export function FillParametersSlide(): React.ReactElement { + return ( +
+
+ + +
Step 3
+

Fill Parameters

+

+ The form is auto-generated from the tool's schema +

+ + +
textToEmoji Parameters
+ +
+
+
+ text * +
+ +
+ +
+
style
+ +
+
+ + + Execute Tool + +
+ + + Required fields are marked with * โ€” optional fields have defaults + +
+
+ ); +} diff --git a/apps/tutorial/src/components/playground-slides/FindToolSlide.tsx b/apps/tutorial/src/components/playground-slides/FindToolSlide.tsx new file mode 100644 index 0000000..7dc79de --- /dev/null +++ b/apps/tutorial/src/components/playground-slides/FindToolSlide.tsx @@ -0,0 +1,70 @@ +'use client'; + +import { motion } from 'framer-motion'; + +export function FindToolSlide(): React.ReactElement { + return ( +
+
+ + +
Step 1
+

Find a Tool

+

Browse or search the registry

+ + +
+
+ ๐Ÿ” + Search tools... +
+
+ +
+ {[ + { name: 'textToEmoji', pkg: '@tpmjs/emoji-magic', desc: 'Convert text to emojis' }, + { name: 'markdownFormat', pkg: '@tpmjs/markdown-formatter', desc: 'Format markdown' }, + { name: 'helloWorld', pkg: '@tpmjs/hello', desc: 'Simple greeting tool' }, + ].map((tool, i) => ( + +
+ fn +
+
+
{tool.name}
+
{tool.pkg}
+
+
{tool.desc}
+
+ ))} +
+
+ + + tpmjs.com โ€” Browse 200+ tools by category + +
+
+ ); +} diff --git a/apps/tutorial/src/components/playground-slides/OpenPlaygroundSlide.tsx b/apps/tutorial/src/components/playground-slides/OpenPlaygroundSlide.tsx new file mode 100644 index 0000000..6d23037 --- /dev/null +++ b/apps/tutorial/src/components/playground-slides/OpenPlaygroundSlide.tsx @@ -0,0 +1,84 @@ +'use client'; + +import { motion } from 'framer-motion'; + +export function OpenPlaygroundSlide(): React.ReactElement { + return ( +
+
+ + +
Step 2
+

Open the Playground

+

Click "Try it" on any tool page

+ + + {/* Mock browser header */} +
+
+
+
+
+
+
+ + tpmjs.com/tool/@tpmjs/emoji-magic/textToEmoji + +
+
+ + {/* Mock tool page */} +
+
+
+
@tpmjs/emoji-magic
+
textToEmoji
+
Convert text to emojis
+
+ + Try it โ†’ + +
+ +
+
+
Parameters
+
text, style?
+
+
+
Health
+
โœ“ Healthy
+
+
+
+ + + +

+ Every tool page has a "Try it" button that opens the playground +

+
+ +
+ ); +} diff --git a/apps/tutorial/src/components/playground-slides/PlaygroundNextStepsSlide.tsx b/apps/tutorial/src/components/playground-slides/PlaygroundNextStepsSlide.tsx new file mode 100644 index 0000000..5915282 --- /dev/null +++ b/apps/tutorial/src/components/playground-slides/PlaygroundNextStepsSlide.tsx @@ -0,0 +1,99 @@ +'use client'; + +import { motion } from 'framer-motion'; + +const features = [ + { + title: 'Test Parameters', + description: 'Understand what each tool expects before integrating', + icon: '๐Ÿงช', + }, + { + title: 'Debug Issues', + description: 'See exact inputs and outputs to troubleshoot', + icon: '๐Ÿ”ง', + }, + { + title: 'Evaluate Quality', + description: 'Check if a tool does what you need before using it', + icon: 'โœ…', + }, + { + title: 'Share Examples', + description: 'Copy the URL to share working examples', + icon: '๐Ÿ”—', + }, +]; + +export function PlaygroundNextStepsSlide(): React.ReactElement { + return ( +
+
+ + +

Use Cases

+

Why the playground is useful

+ +
+ {features.map((feature, index) => ( + +
{feature.icon}
+
{feature.title}
+
{feature.description}
+
+ ))} +
+ + + + Try the Playground + + + + + + Every tool on tpmjs.com has a playground โ€” try any of them + +
+
+ ); +} diff --git a/apps/tutorial/src/components/playground-slides/PlaygroundWelcomeSlide.tsx b/apps/tutorial/src/components/playground-slides/PlaygroundWelcomeSlide.tsx new file mode 100644 index 0000000..bef8b60 --- /dev/null +++ b/apps/tutorial/src/components/playground-slides/PlaygroundWelcomeSlide.tsx @@ -0,0 +1,87 @@ +'use client'; + +import { motion } from 'framer-motion'; + +export function PlaygroundWelcomeSlide(): React.ReactElement { + return ( +
+
+ + + + + Try Before You Install + + + + + + Interactive Playground + + + + + Test any tool directly in your browser + + + + No installation required โ€” execute tools live and see results instantly + + + + + + + + Press any key + +
+ ); +} diff --git a/apps/tutorial/src/components/playground-slides/SeeResultsSlide.tsx b/apps/tutorial/src/components/playground-slides/SeeResultsSlide.tsx new file mode 100644 index 0000000..c924573 --- /dev/null +++ b/apps/tutorial/src/components/playground-slides/SeeResultsSlide.tsx @@ -0,0 +1,85 @@ +'use client'; + +import { motion } from 'framer-motion'; + +export function SeeResultsSlide(): React.ReactElement { + return ( +
+
+ + +
Step 4
+

See Results

+

Tool executes in a secure sandbox

+ +
+ +
Input
+
+              {JSON.stringify(
+                {
+                  text: 'Hello world, I love coding!',
+                  style: 'expressive',
+                },
+                null,
+                2
+              )}
+            
+
+ + +
+
+
Success
+
+
+              {JSON.stringify(
+                {
+                  result: '๐Ÿ‘‹๐ŸŒ, ๐Ÿ’–๐Ÿ’ป!',
+                  emoji_count: 4,
+                },
+                null,
+                2
+              )}
+            
+ +
+ + +
+
127ms
+
Execution time
+
+
+
โœ“
+
Sandboxed
+
+
+
JSON
+
Output format
+
+
+
+
+ ); +}