content: update tutorial slides with grounded TPMJS content

- WelcomeSlide: "The missing layer between npm and AI agents"
- ProblemSlide: "npm has 2 million packages. Which ones work?"
- SolutionSlide: Registry that extracts schemas, scores quality, checks health
- HowItWorksSlide: Automated pipeline flow
- DiscoverySlide: Schema extraction from sandbox
- IntegrationSlide: Quality scoring algorithm
- QualitySlide: Health checks (import + execution)
- ToolDetailSlide: What we store (inputSchema, returnSchema, envKeys, tier)
- GetStartedSlide: CTAs with accurate descriptions

All content now grounded in actual codebase functionality.
Includes TPMJS_TALK.md as source of truth document.
This commit is contained in:
Ajax Davis 2025-12-29 11:40:39 +10:00
parent b279be2a25
commit 70d0c5ba94
10 changed files with 532 additions and 121 deletions

View file

@ -24,55 +24,54 @@ export function DiscoverySlide(): React.ReactElement {
transition={{ type: 'spring', stiffness: 200, delay: 0.2 }}
className="text-6xl mb-8"
>
🔍
</motion.div>
<h2 className="text-5xl md:text-6xl font-bold text-white mb-4">Two Users, One Surface</h2>
<h2 className="text-5xl md:text-6xl font-bold text-white mb-4">Schema Extraction</h2>
<p className="text-xl text-white/40 mb-12">
Same registry. <span className="text-cyan-400 font-semibold">Different clients.</span>
The hard part.{' '}
<span className="text-cyan-400 font-semibold">We run your code in a sandbox.</span>
</p>
{/* Two user types */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 mt-8 max-w-4xl mx-auto">
<motion.div
initial={{ opacity: 0, x: -30 }}
animate={{ opacity: 1, x: 0 }}
transition={{ delay: 0.5 }}
className="p-6 rounded-2xl bg-white/5 border border-white/10 text-left"
>
<div className="text-4xl mb-4">👨💻</div>
<div className="text-2xl font-bold text-cyan-400 mb-3">Engineers browsing</div>
<ul className="space-y-2 text-white/60">
<li>&quot;Show me the best extraction tools&quot;</li>
<li>&quot;I need one that supports screenshots&quot;</li>
<li>&quot;I need maintained + documented&quot;</li>
</ul>
</motion.div>
<motion.div
initial={{ opacity: 0, x: 30 }}
animate={{ opacity: 1, x: 0 }}
transition={{ delay: 0.7 }}
className="p-6 rounded-2xl bg-white/5 border border-white/10 text-left"
>
<div className="text-4xl mb-4">🤖</div>
<div className="text-2xl font-bold text-purple-400 mb-3">Agents selecting</div>
<ul className="space-y-2 text-white/60">
<li>&quot;I need to scrape a URL into markdown&quot;</li>
<li>&quot;I need to summarize a PDF with citations&quot;</li>
<li>&quot;I need a company research tool&quot;</li>
</ul>
</motion.div>
</div>
{/* Code block showing extraction */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.5 }}
className="max-w-2xl mx-auto p-6 rounded-xl bg-[#1e1e2e] text-left font-mono text-sm"
>
<div className="text-white/40 mb-3">
{/* comment */}
{'// We extract this from your actual code:'}
</div>
<div className="text-purple-400">inputSchema: {'{'}</div>
<div className="text-white/80 pl-4">
type: <span className="text-emerald-400">&quot;object&quot;</span>,
</div>
<div className="text-white/80 pl-4">properties: {'{'}</div>
<div className="text-white/80 pl-8">
url: {'{'} type: <span className="text-emerald-400">&quot;string&quot;</span>, format:{' '}
<span className="text-emerald-400">&quot;uri&quot;</span> {'}'}
</div>
<div className="text-white/80 pl-8">
timeout: {'{'} type: <span className="text-emerald-400">&quot;number&quot;</span>,
default: <span className="text-cyan-400">30000</span> {'}'}
</div>
<div className="text-white/80 pl-4">{'}'}</div>
<div className="text-purple-400">{'}'}</div>
</motion.div>
{/* Key insight */}
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ delay: 1.2 }}
className="mt-12 text-white/40 text-lg"
className="mt-8 text-white/40 text-lg"
>
Results are <span className="text-emerald-400 font-semibold">tool-shaped</span>, not just package-shaped.
Not documentation.{' '}
<span className="text-emerald-400 font-semibold">
Ground truth from TypeScript types.
</span>
</motion.div>
</motion.div>
</div>

View file

@ -6,21 +6,21 @@ const links = [
{
label: 'Browse Tools',
href: 'https://tpmjs.com/tool-search',
description: 'Use as a discovery portal',
description: 'Search by name, category, quality',
icon: '🔍',
gradient: 'from-cyan-500 to-blue-500',
},
{
label: 'Publish a Tool',
href: 'https://tpmjs.com/docs/publishing',
description: 'Clean metadata + examples',
description: 'Add tpmjs-tool keyword to npm',
icon: '📦',
gradient: 'from-purple-500 to-pink-500',
},
{
label: 'The Playground',
href: 'https://tpmjs.com/playground',
description: 'Try tools before adopting',
description: 'Run tools in browser sandbox',
icon: '🎮',
gradient: 'from-emerald-500 to-teal-500',
},
@ -61,8 +61,10 @@ export function GetStartedSlide(): React.ReactElement {
🚀
</motion.div>
<h2 className="text-5xl md:text-7xl font-bold text-white mb-4">Try It</h2>
<p className="text-xl md:text-2xl text-white/40 mb-16">Discovery chaos is optional</p>
<h2 className="text-5xl md:text-7xl font-bold text-white mb-4">Get Started</h2>
<p className="text-xl md:text-2xl text-white/40 mb-16">
Indexed automatically. Updated every 2 minutes.
</p>
{/* CTA buttons */}
<div className="flex flex-col md:flex-row items-center justify-center gap-6">
@ -100,7 +102,13 @@ export function GetStartedSlide(): React.ReactElement {
initial={{ x: -10 }}
whileHover={{ x: 0 }}
>
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<svg
aria-hidden="true"
className="w-5 h-5"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
@ -120,7 +128,7 @@ export function GetStartedSlide(): React.ReactElement {
transition={{ delay: 1.2 }}
className="mt-16 text-white/30 text-sm"
>
Tools are inevitable. Discovery chaos isn&apos;t.
The missing layer between npm and AI agents.
</motion.div>
</motion.div>
</div>

View file

@ -3,10 +3,10 @@
import { motion } from 'framer-motion';
const steps = [
{ icon: '📝', label: 'What it does', description: 'Description, category, tags' },
{ icon: '⚙️', label: 'How to call it', description: 'Inputs, schema, examples' },
{ icon: '🔑', label: 'What it needs', description: 'Env vars, auth hints' },
{ icon: '📊', label: 'Signals', description: 'Downloads, health, freshness' },
{ icon: '📦', label: 'npm publish', description: 'Add tpmjs-tool keyword' },
{ icon: '🔄', label: 'Auto-sync', description: 'Indexed in ~2 minutes' },
{ icon: '⚙️', label: 'Schema extracted', description: 'From actual code' },
{ icon: '✅', label: 'Health checked', description: 'Import + execution' },
];
export function HowItWorksSlide(): React.ReactElement {
@ -21,13 +21,13 @@ export function HowItWorksSlide(): React.ReactElement {
transition={{ duration: 0.8 }}
className="relative z-10 max-w-5xl w-full"
>
<h2 className="text-5xl md:text-6xl font-bold text-white mb-4">What TPMJS Stores</h2>
<p className="text-xl text-white/40 mb-16">For each tool, we expose the useful stuff</p>
<h2 className="text-5xl md:text-6xl font-bold text-white mb-4">How It Works</h2>
<p className="text-xl text-white/40 mb-16">Automated pipeline. No manual curation.</p>
{/* Flow diagram */}
<div className="flex flex-col md:flex-row items-center justify-center gap-4 md:gap-0">
{steps.map((step, index) => (
<div key={index} className="flex items-center">
<div key={step.label} className="flex items-center">
{/* Step card */}
<motion.div
initial={{ opacity: 0, y: 30 }}
@ -61,6 +61,7 @@ export function HowItWorksSlide(): React.ReactElement {
>
<div className="w-12 h-px bg-gradient-to-r from-cyan-500/50 to-purple-500/50" />
<svg
aria-hidden="true"
className="w-4 h-4 text-purple-500/50 -ml-1"
fill="currentColor"
viewBox="0 0 20 20"

View file

@ -4,14 +4,13 @@ import { motion } from 'framer-motion';
import { useEffect, useState } from 'react';
const codeLines = [
{ text: '// Faster tool evaluation', delay: 0.5 },
{ text: 'const tool = await tpmjs.find({', delay: 0.8 },
{ text: " capability: 'web-scraping',", delay: 1.1 },
{ text: " minQuality: 0.8", delay: 1.4 },
{ text: '});', delay: 1.7 },
{ text: '', delay: 2.0 },
{ text: '// Schema + examples included', delay: 2.2 },
{ text: 'console.log(tool.schema, tool.examples);', delay: 2.5 },
{ text: '// Quality score: 0.00 - 1.00', delay: 0.5 },
{ text: "const tier = tier === 'rich' ? 0.6 : 0.4;", delay: 0.8 },
{ text: 'const downloads = Math.min(0.2, log10(d));', delay: 1.1 },
{ text: 'const stars = Math.min(0.1, log10(s));', delay: 1.4 },
{ text: '', delay: 1.7 },
{ text: '// Rich = has params, returns, env', delay: 2.0 },
{ text: 'const score = tier + downloads + stars;', delay: 2.3 },
];
function TypewriterLine({ text, delay }: { text: string; delay: number }) {
@ -40,18 +39,15 @@ function TypewriterLine({ text, delay }: { text: string; delay: number }) {
return () => clearTimeout(timeout);
}, [text, delay]);
// Syntax highlighting
const highlightedText = displayText
.replace(/(import|from|const|await)/g, '<span class="text-purple-400">$1</span>')
.replace(/('.*?')/g, '<span class="text-emerald-400">$1</span>')
.replace(/(\/\/.*)/g, '<span class="text-white/30">$1</span>')
.replace(/(\{|\}|\(|\))/g, '<span class="text-yellow-300">$1</span>');
// Simple text display without syntax highlighting to avoid dangerouslySetInnerHTML
const isComment = displayText.startsWith('//');
return (
<div
className="font-mono text-sm md:text-base text-white/80 leading-relaxed"
dangerouslySetInnerHTML={{ __html: highlightedText || '&nbsp;' }}
/>
className={`font-mono text-sm md:text-base leading-relaxed ${isComment ? 'text-white/30' : 'text-white/80'}`}
>
{displayText || '\u00A0'}
</div>
);
}
@ -73,11 +69,11 @@ export function IntegrationSlide(): React.ReactElement {
transition={{ type: 'spring', stiffness: 200, delay: 0.2 }}
className="text-6xl mb-8"
>
🔌
📊
</motion.div>
<h2 className="text-5xl md:text-6xl font-bold text-white mb-4">Immediate Benefits</h2>
<p className="text-xl text-white/40 mb-12">Even if you do nothing else</p>
<h2 className="text-5xl md:text-6xl font-bold text-white mb-4">Quality Scoring</h2>
<p className="text-xl text-white/40 mb-12">Deliberately simple. Not trying to be clever.</p>
{/* Code block */}
<motion.div
@ -96,8 +92,8 @@ export function IntegrationSlide(): React.ReactElement {
{/* Code content */}
<div className="bg-[#1e1e2e] p-6 rounded-b-xl text-left overflow-x-auto">
{codeLines.map((line, index) => (
<TypewriterLine key={index} text={line.text} delay={line.delay} />
{codeLines.map((line) => (
<TypewriterLine key={line.text || line.delay} text={line.text} delay={line.delay} />
))}
<motion.span
animate={{ opacity: [1, 0, 1] }}
@ -107,19 +103,19 @@ export function IntegrationSlide(): React.ReactElement {
</div>
</motion.div>
{/* Benefits badges */}
{/* Score factors */}
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ delay: 3 }}
className="mt-8 flex flex-wrap justify-center gap-3"
>
{['Less spelunking', 'Schemas + examples', 'Shared vocabulary', 'Tool visibility'].map((benefit) => (
{['Tier: 40-60%', 'Downloads: 0-20%', 'Stars: 0-10%', 'Richness: 0-10%'].map((factor) => (
<span
key={benefit}
className="px-3 py-1 rounded-full bg-emerald-500/10 border border-emerald-500/20 text-emerald-400/70 text-sm"
key={factor}
className="px-3 py-1 rounded-full bg-cyan-500/10 border border-cyan-500/20 text-cyan-400/70 text-sm font-mono"
>
{benefit}
{factor}
</span>
))}
</motion.div>

View file

@ -17,9 +17,9 @@ export function ProblemSlide(): React.ReactElement {
return (
<div className="relative flex flex-col items-center justify-center h-full px-8 text-center">
{/* Floating chaotic icons */}
{floatingIcons.map((item, index) => (
{floatingIcons.map((item) => (
<motion.div
key={index}
key={item.icon}
className="absolute text-4xl md:text-5xl opacity-20"
initial={{ opacity: 0, scale: 0 }}
animate={{
@ -73,13 +73,13 @@ export function ProblemSlide(): React.ReactElement {
😵
</motion.div>
<h2 className="text-5xl md:text-6xl font-bold text-white mb-6">Tool Sprawl</h2>
<h2 className="text-5xl md:text-6xl font-bold text-white mb-6">The Problem</h2>
<p className="text-xl md:text-2xl text-white/60 leading-relaxed max-w-2xl">
In modern agent stacks, tools are the{' '}
<span className="text-red-400 font-semibold">real product surface area</span>.
npm has <span className="text-red-400 font-semibold">2 million packages</span>.
<br />
But discovery is the <span className="text-orange-400 font-semibold">bottleneck</span>.
Which ones are AI-callable tools? Which ones{' '}
<span className="text-orange-400 font-semibold">actually work</span>?
</p>
<motion.div
@ -88,17 +88,19 @@ export function ProblemSlide(): React.ReactElement {
transition={{ delay: 1 }}
className="mt-12 flex flex-wrap justify-center gap-4"
>
{['Dozens of packages', 'Missing schemas', 'Vague READMEs', 'Unknown status'].map((word, i) => (
<motion.span
key={word}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 1.2 + i * 0.1 }}
className="px-4 py-2 rounded-full border border-red-500/30 text-red-400/60 text-sm font-mono"
>
{word}
</motion.span>
))}
{["Can't find them", "Can't trust them", "Can't compare them", 'No schemas'].map(
(word, i) => (
<motion.span
key={word}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 1.2 + i * 0.1 }}
className="px-4 py-2 rounded-full border border-red-500/30 text-red-400/60 text-sm font-mono"
>
{word}
</motion.span>
)
)}
</motion.div>
</motion.div>
</div>

View file

@ -28,7 +28,7 @@ function AnimatedGauge({ value, delay = 0 }: { value: number; delay?: number })
return (
<div className="relative w-32 h-32">
<svg className="w-full h-full transform -rotate-90">
<svg aria-hidden="true" className="w-full h-full transform -rotate-90">
{/* Background circle */}
<circle cx="64" cy="64" r="45" fill="none" stroke="rgba(255,255,255,0.1)" strokeWidth="8" />
{/* Progress circle */}
@ -58,10 +58,10 @@ function AnimatedGauge({ value, delay = 0 }: { value: number; delay?: number })
}
const qualityFactors = [
{ name: 'Quality Signals', icon: '📊', score: 95, color: 'cyan', desc: 'Docs, schema, adoption' },
{ name: 'Health Checks', icon: '💚', score: 88, color: 'emerald', desc: 'Imports, exports, runs' },
{ name: 'The Playground', icon: '🎮', score: 92, color: 'purple', desc: 'Try before you adopt' },
{ name: 'Remote Execution', icon: '☁️', score: 85, color: 'yellow', desc: 'Optional sandbox' },
{ name: 'Import Health', icon: '📦', score: 95, color: 'cyan', desc: 'Can we require() it?' },
{ name: 'Execution Health', icon: '▶️', score: 88, color: 'emerald', desc: 'Does it run at all?' },
{ name: 'HEALTHY', icon: '✅', score: 100, color: 'emerald', desc: 'Passed both checks' },
{ name: 'BROKEN', icon: '❌', score: 0, color: 'yellow', desc: 'Labeled, not hidden' },
];
export function QualitySlide(): React.ReactElement {
@ -85,8 +85,10 @@ export function QualitySlide(): React.ReactElement {
</motion.div>
<h2 className="text-5xl md:text-6xl font-bold text-white mb-4">The Multipliers</h2>
<p className="text-xl text-white/40 mb-12">Extra leverage when you&apos;re ready</p>
<h2 className="text-5xl md:text-6xl font-bold text-white mb-4">Health Checks</h2>
<p className="text-xl text-white/40 mb-12">
We don&apos;t hide broken tools. We <span className="text-yellow-400">label them</span>.
</p>
{/* Main gauge */}
<motion.div

View file

@ -29,14 +29,14 @@ export function SolutionSlide(): React.ReactElement {
</motion.div>
<h2 className="text-5xl md:text-6xl font-bold text-white mb-6">TPMJS</h2>
<h2 className="text-5xl md:text-6xl font-bold text-white mb-6">What TPMJS Is</h2>
<p className="text-xl md:text-2xl text-white/60 leading-relaxed mb-12 max-w-2xl">
A registry that indexes AI-tool packages and exposes{' '}
<span className="text-cyan-400 font-semibold">normalized, enriched information</span>
A <span className="text-cyan-400 font-semibold">registry</span> that indexes npm packages
for AI tool use.
<br />
so agents and engineers can{' '}
<span className="text-emerald-400 font-semibold">discover the right tool faster</span>.
<span className="text-emerald-400 font-semibold">Extracts schemas from code</span>. Scores
quality. Checks health.
</p>
{/* Organized grid of icons */}
@ -46,9 +46,9 @@ export function SolutionSlide(): React.ReactElement {
transition={{ delay: 0.5 }}
className="grid grid-cols-4 md:grid-cols-6 gap-4 max-w-lg mx-auto"
>
{gridItems.map((item, index) => (
{gridItems.map((item) => (
<motion.div
key={index}
key={item.icon}
initial={{ opacity: 0, scale: 0, y: 20 }}
animate={{ opacity: 1, scale: 1, y: 0 }}
transition={{
@ -70,7 +70,7 @@ export function SolutionSlide(): React.ReactElement {
transition={{ delay: 1.5 }}
className="mt-12 flex flex-wrap justify-center gap-4"
>
{['Catalog', 'Metadata layer', 'Search surface', 'Consistent contract'].map((word, i) => (
{['Registry', 'Schema extraction', 'Quality scoring', 'Health checks'].map((word, i) => (
<motion.span
key={word}
initial={{ opacity: 0, y: 20 }}

View file

@ -14,8 +14,10 @@ export function ToolDetailSlide(): React.ReactElement {
transition={{ duration: 0.8 }}
className="relative z-10 max-w-4xl w-full"
>
<h2 className="text-5xl md:text-6xl font-bold text-white mb-4">Tool-Shaped Results</h2>
<p className="text-xl text-white/40 mb-12">Remove guesswork before you integrate</p>
<h2 className="text-5xl md:text-6xl font-bold text-white mb-4">What We Store</h2>
<p className="text-xl text-white/40 mb-12">
Everything an agent needs to <span className="text-cyan-400">call a tool correctly</span>
</p>
{/* Mock tool card */}
<motion.div
@ -91,15 +93,18 @@ export function ToolDetailSlide(): React.ReactElement {
transition={{ delay: 1 }}
className="p-4 rounded-lg bg-black/30 font-mono text-sm"
>
<div className="text-white/40 mb-2">// Input Schema</div>
<div className="text-cyan-400">
query: <span className="text-white/60">string</span>
<div className="text-white/40 mb-2">{'// Extracted from actual code'}</div>
<div className="text-purple-400">
inputSchema: <span className="text-white/60">JSON Schema</span>
</div>
<div className="text-cyan-400">
limit?: <span className="text-white/60">number</span>
<div className="text-purple-400">
returnSchema: <span className="text-white/60">JSON Schema</span>
</div>
<div className="text-cyan-400">
domains?: <span className="text-white/60">string[]</span>
<div className="text-purple-400">
envKeys: <span className="text-white/60">[&quot;API_KEY&quot;]</span>
</div>
<div className="text-purple-400">
tier: <span className="text-emerald-400">&quot;rich&quot;</span>
</div>
</motion.div>
</motion.div>

View file

@ -56,7 +56,8 @@ export function WelcomeSlide(): React.ReactElement {
transition={{ duration: 0.8, delay: 0.5 }}
className="mt-6 text-2xl md:text-3xl text-white/60 font-light max-w-2xl"
>
Tool Discovery for AI Agents
The missing layer between &quot;LLMs can call tools&quot; and &quot;which tool,
exactly?&quot;
</motion.p>
{/* Decorative line */}
@ -79,7 +80,13 @@ export function WelcomeSlide(): React.ReactElement {
transition={{ duration: 1.5, repeat: Number.POSITIVE_INFINITY, ease: 'easeInOut' }}
className="text-white/40"
>
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<svg
aria-hidden="true"
className="w-6 h-6"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"