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 20f5fcc4b0
commit bda49615fb
10 changed files with 532 additions and 121 deletions

391
TPMJS_TALK.md Normal file
View file

@ -0,0 +1,391 @@
# TPMJS: The Missing Layer Between "LLMs Can Call Tools" and "Which Tool, Exactly?"
---
## The Setup
You're building an AI agent. It needs to do things in the world—scrape a webpage, send an email, query a database, generate an image. These capabilities come from **tools**.
The problem isn't that tools don't exist. They do. Thousands of them. The problem is:
- **You can't find them.** npm has 2 million packages. Which ones are AI-callable tools? Which ones actually work?
- **You can't trust them.** No schema. No examples. README says "AI-ready" but the function signature is `(opts: any) => Promise<any>`.
- **You can't compare them.** Three packages do "web scraping." Which one handles JavaScript rendering? Which one returns structured data? Which one is maintained?
Discovery is the bottleneck. Not capability—discovery.
---
## What TPMJS Actually Is
TPMJS is infrastructure. Specifically:
1. **A registry** that indexes npm packages designed for AI tool use
2. **A metadata extraction pipeline** that pulls schemas directly from code
3. **A quality scoring system** that ranks tools by completeness and adoption
4. **A health monitoring system** that verifies tools actually work
5. **A playground** where you can test tools before integrating them
It's not magic. It's plumbing. Good plumbing.
---
## How It Works (The Technical Reality)
### Discovery: Finding Tools in the Wild
TPMJS runs three automated sync jobs:
**1. npm Changes Feed (every 2 minutes)**
```
npm registry → /_changes endpoint → filter for tpmjs-tool keyword → process
```
This catches new packages and updates in near-real-time. We track sequence numbers so we never reprocess.
**2. Keyword Search (every 15 minutes)**
```
npm search "tpmjs-tool" → up to 250 results → validate → ingest
```
Backup mechanism. Catches anything the changes feed missed.
**3. Metrics Sync (hourly)**
```
for each package → fetch download stats → recalculate quality scores → update health status
```
Keeps the registry fresh.
### The Publisher Contract
To get indexed, a package needs two things:
```json
{
"name": "@acme/my-tool",
"keywords": ["tpmjs-tool"],
"tpmjs": {
"category": "web-scraping",
"description": "Scrapes URLs and returns structured markdown"
}
}
```
That's the minimum. Category + description. Everything else is either optional or auto-extracted.
**Categories are fixed** (12 total): web-scraping, data-processing, file-operations, communication, database, api-integration, image-processing, text-analysis, automation, ai-ml, security, monitoring.
Why fixed? Because agents need to filter. "Give me all database tools" has to mean something.
### Schema Extraction: The Hard Part
Here's what makes TPMJS different from a glorified npm search.
When we ingest a package, we don't just read the README. We **execute it in a sandbox** and extract the actual schema:
```
1. Spin up isolated executor (Railway)
2. npm install the package
3. Import and inspect exports
4. Extract JSON Schema from TypeScript types
5. Store schema in database
```
The result:
```json
{
"name": "scrapeUrl",
"inputSchema": {
"type": "object",
"properties": {
"url": { "type": "string", "format": "uri" },
"waitForSelector": { "type": "string" },
"timeout": { "type": "number", "default": 30000 }
},
"required": ["url"]
}
}
```
This isn't documentation. This is **extracted from the actual function signature**. It's ground truth.
If the author provides a schema in the `tpmjs` field, we use that. If not, we extract it. Either way, every tool in the registry has a schema.
### Quality Scoring: Ranking What Matters
Every tool gets a score from 0.00 to 1.00:
```typescript
// Base score from metadata completeness
const tierScore = tier === 'rich' ? 0.6 : 0.4;
// Adoption signals
const downloadsScore = Math.min(0.2, Math.log10(downloads + 1) / 15);
const starsScore = Math.min(0.1, Math.log10(githubStars + 1) / 10);
// Metadata richness bonus
let richnessScore = 0;
if (hasParameters) richnessScore += 0.04;
if (hasReturns) richnessScore += 0.03;
if (hasEnvVars) richnessScore += 0.03;
```
**Tier** is binary:
- **Minimal**: Just category + description (40% base)
- **Rich**: Has parameters, returns, env vars, or framework tags (60% base)
The formula is deliberately simple. We're not trying to be clever. We're trying to surface tools that are well-documented and actually used.
### Health Checks: Does It Actually Work?
Two checks, run during sync and periodically:
**1. Import Health**
```
Can we require() this package without it exploding?
```
You'd be surprised how many npm packages fail this.
**2. Execution Health**
```
Can we call the main function with minimal parameters without throwing?
```
Not a full test suite. Just "does it run at all?"
Results: `HEALTHY`, `BROKEN`, or `UNKNOWN`.
Broken tools still appear in the registry (with a warning). We don't hide them—we label them.
---
## The Data Model
Here's what we actually store:
### Package (npm package level)
```
npmPackageName (unique)
npmVersion, npmDescription, npmRepository, npmLicense
npmKeywords[], npmReadme, npmAuthor
category (enum)
tier ('minimal' | 'rich')
discoveryMethod ('changes-feed' | 'keyword')
npmDownloadsLastMonth, githubStars
frameworks[] (vercel-ai, langchain, etc.)
env[] (required environment variables)
```
### Tool (individual callable within a package)
```
packageId (FK)
name (export name: "scrapeUrl", "default", etc.)
description
inputSchema (JSON Schema)
schemaSource ('extracted' | 'author')
qualityScore (0.00-1.00)
importHealth, executionHealth (HEALTHY | BROKEN | UNKNOWN)
toolDiscoverySource ('auto' | 'manual')
```
One package can have multiple tools. `@acme/web-tools` might export `scrapeUrl`, `screenshotPage`, and `extractLinks`. Each is a separate tool with its own schema and health status.
### Simulation (playground execution)
```
toolId
userPrompt (what the user asked)
parameters (JSON, what was passed to the tool)
status (pending | running | success | error | timeout)
executionTimeMs, output, error
model, agentSteps
```
We track every playground execution. Not for surveillance—for debugging and improving the system.
---
## The API
### Search & Discovery
```
GET /api/tools
?q=scrape
&category=web-scraping
&importHealth=HEALTHY
&executionHealth=HEALTHY
&limit=20
&offset=0
→ Returns tools sorted by quality score
```
```
GET /api/tools/search
?q=I need to extract text from PDFs
→ BM25-ranked semantic search
```
### Execution
```
POST /api/tools/execute/{toolId}
{
"prompt": "Scrape the homepage of Hacker News",
"parameters": { "url": "https://news.ycombinator.com" }
}
→ Server-Sent Events stream with:
- Agent reasoning steps
- Tool call results
- Final output
```
Rate limited: 10 requests per IP per hour. We're not a free compute platform.
### Schema Operations
```
POST /api/tools/extract-schema
{ "packageName": "@acme/my-tool", "toolName": "scrapeUrl" }
→ Forces re-extraction of schema from source
```
---
## The Playground
A Next.js app where you can:
1. **Browse tools** by category, health status, quality score
2. **Inspect schemas** before you commit to anything
3. **Test execution** with an AI agent
4. **See real responses** with actual latency and token usage
It's not a demo. It's a debugging tool. "Does this tool do what I think it does?" Answer that question in 30 seconds instead of 30 minutes.
---
## What This Enables
### For Engineers Building Agents
Before TPMJS:
```
1. Search npm for "web scraper"
2. Get 500 results
3. Click through 20 of them
4. Read READMEs that say "easy to use!"
5. npm install three of them
6. Write test code for each
7. Find out two are broken
8. Pick the one that works
9. Hope it keeps working
```
After TPMJS:
```
1. Search tpmjs.com for "web scraper"
2. Filter by HEALTHY status
3. Sort by quality score
4. Click top result
5. See exact input schema
6. Test in playground
7. Integrate
```
### For Tool Authors
Before TPMJS:
```
Publish to npm → hope someone finds it → no visibility into usage
```
After TPMJS:
```
Publish to npm with tpmjs-tool keyword → indexed within 2 minutes →
schema auto-extracted → quality scored → discoverable by search →
execution stats tracked
```
Your tool becomes findable. Not just by humans grepping npm, but by agents querying the registry API.
### For Agents (Yes, Really)
Agents can query TPMJS at runtime:
```typescript
const tools = await fetch('https://tpmjs.com/api/tools?' + new URLSearchParams({
q: 'send email',
executionHealth: 'HEALTHY',
limit: '5'
})).then(r => r.json());
// Agent now has 5 working email tools with full schemas
// It can pick the best one for this specific task
```
This is the endgame. Not humans browsing a registry—agents dynamically selecting tools based on capability, health, and fit.
---
## What TPMJS Is Not
**Not a package manager.** We don't host packages. npm does that. We index and enrich.
**Not an execution platform.** The playground runs tools for testing. Production execution is your responsibility.
**Not a security guarantee.** We check if tools work. We don't audit them for malice. Same rules as npm: don't run untrusted code.
**Not magic.** We're not using AI to understand what tools do. We're extracting schemas and running health checks. Boring, reliable, debuggable.
---
## The Technical Stack
- **Database**: PostgreSQL via Prisma
- **Web**: Next.js 16 (App Router)
- **Deployment**: Vercel (web) + Railway (sandbox executor)
- **Sync**: Vercel Cron + GitHub Actions backup
- **AI**: Vercel AI SDK for playground execution
- **Monorepo**: Turborepo + pnpm
Key internal packages:
- `@tpmjs/npm-client` — npm registry integration
- `@tpmjs/package-executor` — sandbox execution client
- `@tpmjs/types` — schema validation and migration
- `@tpmjs/db` — Prisma client and models
---
## Current State
- **~100 tools indexed** (and growing with every npm publish)
- **12 categories** covering most agent use cases
- **Automated sync** running 24/7
- **Health checks** on every tool
- **Schema extraction** working for TypeScript and JavaScript
- **Playground** functional for testing
---
## The Pitch (Finally)
Tools are the API surface of AI agents. The ecosystem is a mess. TPMJS is the index.
We don't compete with npm—we sit on top of it. We don't replace tool authors—we make them discoverable. We don't build agents—we give agents a way to find their tools.
Discovery is the bottleneck. We're fixing discovery.
---
## Try It
- **Browse**: https://tpmjs.com/tool-search
- **Playground**: https://tpmjs.com/playground
- **Publish**: Add `tpmjs-tool` keyword + `tpmjs` field to your package.json
- **API**: `GET https://tpmjs.com/api/tools`
---
*Tools are inevitable. Discovery chaos isn't.*

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"