kopia lustrzana https://github.com/transitive-bullshit/chatgpt-api
feat: web improvements
rodzic
72750d1361
commit
e388bcee46
|
@ -124,6 +124,7 @@ export function registerV1StripeWebhook(app: HonoApp) {
|
|||
assert(deployment, 404, `deployment "${deploymentId}" not found`)
|
||||
}
|
||||
const { project } = consumer
|
||||
assert(project, 404, `project "${projectId}" not found`)
|
||||
|
||||
// TODO: Treat this as a transaction...
|
||||
await Promise.all([
|
||||
|
@ -158,13 +159,12 @@ export function registerV1StripeWebhook(app: HonoApp) {
|
|||
const { consumerId, userId, projectId, deploymentId, plan } =
|
||||
subscription.metadata
|
||||
|
||||
// TODO: This should be coming from Stripe Checkout, and a very flow
|
||||
// follow-up webhook event should record the subscription and
|
||||
// initialize the consumer, but it feels wrong to me to just be
|
||||
// logging and ignore this event. In the future, if we support both
|
||||
// Stripe Checkout and non-Stripe Checkout-based subscription flows,
|
||||
// then this codepath should act very similarly to
|
||||
// `customer.subscription.updated`.
|
||||
// TODO: This should be coming from Stripe Checkout, and a subsequent
|
||||
// webhook event should record the subscription and initialize the
|
||||
// consumer, but it feels wrong to me to just be logging and ignore
|
||||
// this event. In the future, if we support both Stripe Checkout and
|
||||
// non-Stripe Checkout-based subscription flows, then this codepath
|
||||
// should act very similarly to `customer.subscription.updated`.
|
||||
if (
|
||||
!consumerId ||
|
||||
!userId ||
|
||||
|
|
|
@ -115,8 +115,17 @@ export async function createStripeCheckoutSession(
|
|||
}
|
||||
}
|
||||
|
||||
assert(
|
||||
pricingPlan,
|
||||
404,
|
||||
`Unable to update stripe subscription for invalid pricing plan "${plan}"`
|
||||
)
|
||||
|
||||
const updateParams: Stripe.SubscriptionUpdateParams = {
|
||||
collection_method: 'charge_automatically',
|
||||
description:
|
||||
pricingPlan.description ??
|
||||
`Subscription to ${project.name} ${pricingPlan.name}`,
|
||||
metadata: {
|
||||
plan: plan ?? null,
|
||||
consumerId: consumer.id,
|
||||
|
@ -126,12 +135,6 @@ export async function createStripeCheckoutSession(
|
|||
}
|
||||
}
|
||||
|
||||
assert(
|
||||
pricingPlan,
|
||||
404,
|
||||
`Unable to update stripe subscription for invalid pricing plan "${plan}"`
|
||||
)
|
||||
|
||||
const items: Stripe.SubscriptionUpdateParams.Item[] = await Promise.all(
|
||||
pricingPlan.lineItems.map(async (lineItem) => {
|
||||
const priceId = await getStripePriceIdForPricingPlanLineItem({
|
||||
|
|
|
@ -26,10 +26,16 @@
|
|||
"@agentic/platform-types": "workspace:*",
|
||||
"@agentic/platform-validators": "workspace:*",
|
||||
"@number-flow/react": "^0.5.10",
|
||||
"@pmndrs/assets": "^1.7.0",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.15",
|
||||
"@radix-ui/react-label": "^2.1.7",
|
||||
"@radix-ui/react-slot": "^1.2.3",
|
||||
"@radix-ui/react-tooltip": "^1.2.7",
|
||||
"@react-three/cannon": "^6.6.0",
|
||||
"@react-three/drei": "^10.2.0",
|
||||
"@react-three/fiber": "^9.1.2",
|
||||
"@react-three/postprocessing": "^3.0.4",
|
||||
"@react-three/rapier": "^2.1.0",
|
||||
"@tanstack/react-form": "^1.12.3",
|
||||
"@tanstack/react-query": "^5.80.10",
|
||||
"@tanstack/react-query-devtools": "^5.80.10",
|
||||
|
@ -50,7 +56,9 @@
|
|||
"react-use": "^17.6.0",
|
||||
"sonner": "^2.0.5",
|
||||
"stripe": "catalog:",
|
||||
"suspend-react": "^0.1.3",
|
||||
"tailwind-merge": "^3.3.1",
|
||||
"three": "^0.177.0",
|
||||
"type-fest": "catalog:"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -58,6 +66,7 @@
|
|||
"@tailwindcss/typography": "^0.5.16",
|
||||
"@types/react": "catalog:",
|
||||
"@types/react-dom": "catalog:",
|
||||
"@types/three": "^0.177.0",
|
||||
"autoprefixer": "^10.4.21",
|
||||
"postcss": "^8.5.6",
|
||||
"tailwindcss": "^4.1.10",
|
||||
|
|
Plik binarny nie jest wyświetlany.
Plik binarny nie jest wyświetlany.
Po Szerokość: | Wysokość: | Rozmiar: 2.2 KiB |
|
@ -0,0 +1,264 @@
|
|||
import Link from 'next/link'
|
||||
|
||||
import { GitHubStarCounter } from '@/components/github-star-counter'
|
||||
import { HeroSimulation2 } from '@/components/hero-simulation-2'
|
||||
import { SupplySideCTA } from '@/components/supply-side-cta'
|
||||
import {
|
||||
calendarBookingUrl,
|
||||
docsUrl,
|
||||
githubUrl,
|
||||
twitterUrl
|
||||
} from '@/lib/config'
|
||||
|
||||
export default function TheSecondBestDamnLandingPageEver() {
|
||||
return (
|
||||
<>
|
||||
{/* Hero section */}
|
||||
<section className='mb-16 relative'>
|
||||
<div className='flex gap-8'>
|
||||
{/* <div className='absolute top-0 bottom-0 left-0 right-0 bg-[url(/dots.svg)] bg-repeat bg-center bg-size-[32px_auto] opacity-30 dark:opacity-100' />
|
||||
|
||||
<div className='absolute top-0 bottom-0 left-0 right-0 bg-[radial-gradient(39%_50%_at_50%_50%,rgba(255,255,255,.3)_0%,rgb(255,255,255)_100%)] dark:bg-[radial-gradient(39%_50%_at_50%_50%,rgba(10,10,10,0)_0%,rgb(10,10,10)_100%)]' /> */}
|
||||
|
||||
<div className='flex flex-col gap-8 relative z-10'>
|
||||
<h1 className='text-center text-balance leading-snug md:leading-none text-4xl font-semibold'>
|
||||
Your API → Paid MCP, Instantly
|
||||
</h1>
|
||||
|
||||
<h5 className='text-center text-lg max-w-2xl'>
|
||||
Run one command to turn any MCP server or OpenAPI service into a
|
||||
paid MCP product,{' '}
|
||||
<em>with built-in distribution to over 20k AI engineers</em>.
|
||||
</h5>
|
||||
|
||||
<SupplySideCTA />
|
||||
</div>
|
||||
|
||||
<div className='w-[40%] h-full min-h-full' />
|
||||
|
||||
<HeroSimulation2 className='absolute! top-[-50%]! left-[30%] w-full h-[200%]!' />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section></section>
|
||||
|
||||
{/* How it works section */}
|
||||
<section className='flex flex-col gap-8 mb-16'>
|
||||
<h2 className='text-center text-balance leading-snug md:leading-none text-3xl font-heading'>
|
||||
How It Works
|
||||
</h2>
|
||||
|
||||
<div>TODO</div>
|
||||
</section>
|
||||
|
||||
{/* Features section */}
|
||||
<section className='flex flex-col gap-8 mb-16'>
|
||||
<h2 className='text-center text-balance leading-snug md:leading-none text-3xl font-heading'>
|
||||
Production-Ready and Extremely Flexible
|
||||
</h2>
|
||||
|
||||
<div className='grid gap-6 max-w-2xl'>
|
||||
<div className='flex flex-col gap-2'>
|
||||
<h4 className='text-center text-balance text-lg font-heading'>
|
||||
Auth
|
||||
</h4>
|
||||
|
||||
<p className='text-sm'>
|
||||
Ship to production fast with Agentic's free, built-in
|
||||
authentication. Email & password, OAuth, GitHub, Google, Twitter,
|
||||
etc – if your origin API requires OAuth credentials, Agentic
|
||||
likely already supports it, and if not,{' '}
|
||||
<Link
|
||||
href={calendarBookingUrl}
|
||||
target='_blank'
|
||||
rel='noopener'
|
||||
className='link'
|
||||
>
|
||||
let me know
|
||||
</Link>
|
||||
.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className='flex flex-col gap-2'>
|
||||
<h4 className='text-center text-balance text-lg font-heading'>
|
||||
Stripe Billing
|
||||
</h4>
|
||||
|
||||
<p className='text-sm'>
|
||||
Charge for your MCP products with a flexible, declarative pricing
|
||||
model built on top of Stripe. Agentic supports almost any
|
||||
combination of fixed and{' '}
|
||||
<span className='font-semibold'>usage-based billing</span> models,
|
||||
both at the MCP level, at the tool-call level, and at the custom
|
||||
metric level (e.g., tokens, image transformations, etc).
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className='flex flex-col gap-2'>
|
||||
<h4 className='text-center text-balance text-lg font-heading'>
|
||||
Support both MCP and HTTP
|
||||
</h4>
|
||||
|
||||
<p className='text-sm'>
|
||||
All agentic products support being used both as a standard MCP
|
||||
server <em>and</em> as an extremely simple HTTP API. MCP is
|
||||
important for interop, discoverability, and future-proofing,
|
||||
whereas being able to call your agentic tools via simple{' '}
|
||||
<em>HTTP POST</em> requests makes tool use easy to debug and makes
|
||||
integration with existing LLM tool calling patterns a breeze. With
|
||||
Agentic, you get the best of both worlds, including future support
|
||||
for unreleased MCP features and related specs.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className='flex flex-col gap-2'>
|
||||
<h4 className='text-center text-balance text-lg font-heading'>
|
||||
API keys
|
||||
</h4>
|
||||
|
||||
<p className='text-sm'>
|
||||
When a customer subscribes to your product, they're given a unique
|
||||
API key. MCP URLs are appended with this API key to correlate
|
||||
usage with their subscription. Customer HTTP tool calls use the
|
||||
same API key as a standard HTTP <em>Authorization</em> header.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className='flex flex-col gap-2'>
|
||||
<h4 className='text-center text-balance text-lg font-heading'>
|
||||
Rate-limiting
|
||||
</h4>
|
||||
|
||||
<p className='text-sm'>
|
||||
All agentic products are protected by durable rate-limiting built
|
||||
on top of Cloudflare's global infrastructure. Customize the
|
||||
default rate-limits, change them based on a customer's pricing
|
||||
plan, or create custom tool-specific overrides. REST assured that
|
||||
your origin API will be safe behind Agentic's robust API gateway.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className='flex flex-col gap-2'>
|
||||
<h4 className='text-center text-balance text-lg font-heading'>
|
||||
Caching
|
||||
</h4>
|
||||
|
||||
<p className='text-sm'>
|
||||
Opt-in to caching with familiar <em>cache-control</em> and{' '}
|
||||
<em>stale-while-revalidate</em> options. MCP tool calls include
|
||||
caching information in their <em>_meta</em> fields, providing
|
||||
parity with standard HTTP headers. All caching takes place in
|
||||
Cloudflare's global edge cache, and caching will only be enabled
|
||||
if you choose to enable it for your product or individual tools.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className='flex flex-col gap-2'>
|
||||
<h4 className='text-center text-balance text-lg font-heading'>
|
||||
Analytics
|
||||
</h4>
|
||||
|
||||
<p className='text-sm'>
|
||||
Agentic tracks all tool calls for usage-based billing and
|
||||
analytics at a fine-grained level, so you can drill in and deeply
|
||||
understand how your customers are using your product.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className='flex flex-col gap-2'>
|
||||
<h4 className='text-center text-balance text-lg font-heading'>
|
||||
Versioning
|
||||
</h4>
|
||||
|
||||
<p className='text-sm'>
|
||||
Just like Vercel, Agentic uses immutable deployments, so every
|
||||
time you make a change to your product's config, pricing, or docs,
|
||||
a unique preview deployment is created for that change. This
|
||||
enables instant rollbacks if there are problems with a deployment.
|
||||
Publishing deployments publicly uses semantic versioning (
|
||||
<em>semver</em>), so your customers can choose how to handle
|
||||
breaking changes.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className='flex flex-col gap-2'>
|
||||
<h4 className='text-center text-balance text-lg font-heading'>
|
||||
That's just the start
|
||||
</h4>
|
||||
|
||||
<p className='text-sm'>
|
||||
<Link href={docsUrl} className='link'>
|
||||
Check out our docs
|
||||
</Link>{' '}
|
||||
for more details on Agentic's MCP API gateway.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Marketplace section */}
|
||||
{/* <section className='flex flex-col gap-8 mb-16'>
|
||||
<h2 className='text-center text-balance leading-snug md:leading-none text-3xl font-heading'>
|
||||
MCP Marketplace
|
||||
</h2>
|
||||
|
||||
<p>
|
||||
<i>Coming soon...</i>
|
||||
</p>
|
||||
</section> */}
|
||||
|
||||
{/* Open source section */}
|
||||
<section className='flex flex-col items-center gap-8 max-w-2xl text-center mb-16'>
|
||||
<h2 className='text-center text-balance leading-snug md:leading-none text-3xl font-heading'>
|
||||
Agentic is 100% Open Source
|
||||
</h2>
|
||||
|
||||
<p className=''>
|
||||
Open source is very dear to my heart, and I couldn't be happier that
|
||||
Agentic is fully OSS. It's written in{' '}
|
||||
<span className='font-semibold'>TypeScript</span> and has a small but
|
||||
vibrant developer community.{' '}
|
||||
<Link
|
||||
href={githubUrl}
|
||||
target='_blank'
|
||||
rel='noopener'
|
||||
className='link'
|
||||
>
|
||||
Check out the source on GitHub
|
||||
</Link>{' '}
|
||||
or{' '}
|
||||
<Link
|
||||
href={twitterUrl}
|
||||
target='_blank'
|
||||
rel='noopener'
|
||||
className='link'
|
||||
>
|
||||
ping me on Twitter with questions / feedback
|
||||
</Link>
|
||||
.
|
||||
</p>
|
||||
|
||||
<GitHubStarCounter />
|
||||
</section>
|
||||
|
||||
{/* Social proof section */}
|
||||
<section className='gap-8 mb-16'>
|
||||
<h2 className='text-center text-balance leading-snug md:leading-none text-3xl font-heading'>
|
||||
TODO: social proof
|
||||
</h2>
|
||||
|
||||
<p className='text-center text-lg max-w-2xl'>TODO</p>
|
||||
</section>
|
||||
|
||||
{/* CTA section */}
|
||||
<section className='flex flex-col gap-12 mb-16'>
|
||||
<h2 className='text-center text-balance leading-snug md:leading-none text-3xl font-heading'>
|
||||
Deploy Your MCP Today
|
||||
</h2>
|
||||
|
||||
<SupplySideCTA variant='github-2' />
|
||||
</section>
|
||||
</>
|
||||
)
|
||||
}
|
|
@ -1,13 +1,8 @@
|
|||
import Link from 'next/link'
|
||||
|
||||
import { DemandSideCTA } from '@/components/demand-side-cta'
|
||||
import { GitHubStarCounter } from '@/components/github-star-counter'
|
||||
import { SupplySideCTA } from '@/components/supply-side-cta'
|
||||
import {
|
||||
calendarBookingUrl,
|
||||
docsUrl,
|
||||
githubUrl,
|
||||
twitterUrl
|
||||
} from '@/lib/config'
|
||||
import { githubUrl, twitterUrl } from '@/lib/config'
|
||||
|
||||
export default function TheBestDamnLandingPageEver() {
|
||||
return (
|
||||
|
@ -20,19 +15,20 @@ export default function TheBestDamnLandingPageEver() {
|
|||
|
||||
<div className='flex flex-col gap-8 relative z-10'>
|
||||
<h1 className='text-center text-balance leading-snug md:leading-none text-4xl font-semibold'>
|
||||
Your API → Paid MCP, Instantly
|
||||
The App Store for LLM Tools
|
||||
</h1>
|
||||
|
||||
<h5 className='text-center text-lg max-w-2xl'>
|
||||
Run one command to turn any MCP server or OpenAPI service into a
|
||||
paid MCP product,{' '}
|
||||
<em>with built-in distribution to over 20k AI engineers</em>.
|
||||
Agentic is a curated marketplace of production-grade LLM tools. All
|
||||
tools are exposed as both MCP servers as well as simple HTTP APIs.
|
||||
</h5>
|
||||
|
||||
<SupplySideCTA />
|
||||
<DemandSideCTA />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section></section>
|
||||
|
||||
{/* How it works section */}
|
||||
<section className='flex flex-col gap-8 mb-16'>
|
||||
<h2 className='text-center text-balance leading-snug md:leading-none text-3xl font-heading'>
|
||||
|
@ -42,162 +38,16 @@ export default function TheBestDamnLandingPageEver() {
|
|||
<div>TODO</div>
|
||||
</section>
|
||||
|
||||
{/* Features section */}
|
||||
{/* Marketplace section */}
|
||||
<section className='flex flex-col gap-8 mb-16'>
|
||||
<h2 className='text-center text-balance leading-snug md:leading-none text-3xl font-heading'>
|
||||
Production-Ready and Extremely Flexible
|
||||
</h2>
|
||||
|
||||
<div className='grid gap-6 max-w-2xl'>
|
||||
<div className='flex flex-col gap-2'>
|
||||
<h4 className='text-center text-balance text-lg font-heading'>
|
||||
Auth
|
||||
</h4>
|
||||
|
||||
<p className='text-sm'>
|
||||
Ship to production fast with Agentic's free, built-in
|
||||
authentication. Email & password, OAuth, GitHub, Google, Twitter,
|
||||
etc – if your origin API requires OAuth credentials, Agentic
|
||||
likely already supports it, and if not,{' '}
|
||||
<Link
|
||||
href={calendarBookingUrl}
|
||||
target='_blank'
|
||||
rel='noopener'
|
||||
className='link'
|
||||
>
|
||||
let me know
|
||||
</Link>
|
||||
.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className='flex flex-col gap-2'>
|
||||
<h4 className='text-center text-balance text-lg font-heading'>
|
||||
Stripe Billing
|
||||
</h4>
|
||||
|
||||
<p className='text-sm'>
|
||||
Charge for your MCP products with a flexible, declarative pricing
|
||||
model built on top of Stripe. Agentic supports almost any
|
||||
combination of fixed and{' '}
|
||||
<span className='font-semibold'>usage-based billing</span> models,
|
||||
both at the MCP level, at the tool-call level, and at the custom
|
||||
metric level (e.g., tokens, image transformations, etc).
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className='flex flex-col gap-2'>
|
||||
<h4 className='text-center text-balance text-lg font-heading'>
|
||||
Support both MCP and HTTP
|
||||
</h4>
|
||||
|
||||
<p className='text-sm'>
|
||||
All agentic products support being used both as a standard MCP
|
||||
server <em>and</em> as an extremely simple HTTP API. MCP is
|
||||
important for interop, discoverability, and future-proofing,
|
||||
whereas being able to call your agentic tools via simple{' '}
|
||||
<em>HTTP POST</em> requests makes tool use easy to debug and makes
|
||||
integration with existing LLM tool calling patterns a breeze. With
|
||||
Agentic, you get the best of both worlds, including future support
|
||||
for unreleased MCP features and related specs.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className='flex flex-col gap-2'>
|
||||
<h4 className='text-center text-balance text-lg font-heading'>
|
||||
API keys
|
||||
</h4>
|
||||
|
||||
<p className='text-sm'>
|
||||
When a customer subscribes to your product, they're given a unique
|
||||
API key. MCP URLs are appended with this API key to correlate
|
||||
usage with their subscription. Customer HTTP tool calls use the
|
||||
same API key as a standard HTTP <em>Authorization</em> header.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className='flex flex-col gap-2'>
|
||||
<h4 className='text-center text-balance text-lg font-heading'>
|
||||
Rate-limiting
|
||||
</h4>
|
||||
|
||||
<p className='text-sm'>
|
||||
All agentic products are protected by durable rate-limiting built
|
||||
on top of Cloudflare's global infrastructure. Customize the
|
||||
default rate-limits, change them based on a customer's pricing
|
||||
plan, or create custom tool-specific overrides. REST assured that
|
||||
your origin API will be safe behind Agentic's robust API gateway.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className='flex flex-col gap-2'>
|
||||
<h4 className='text-center text-balance text-lg font-heading'>
|
||||
Caching
|
||||
</h4>
|
||||
|
||||
<p className='text-sm'>
|
||||
Opt-in to caching with familiar <em>cache-control</em> and{' '}
|
||||
<em>stale-while-revalidate</em> options. MCP tool calls include
|
||||
caching information in their <em>_meta</em> fields, providing
|
||||
parity with standard HTTP headers. All caching takes place in
|
||||
Cloudflare's global edge cache, and caching will only be enabled
|
||||
if you choose to enable it for your product or individual tools.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className='flex flex-col gap-2'>
|
||||
<h4 className='text-center text-balance text-lg font-heading'>
|
||||
Analytics
|
||||
</h4>
|
||||
|
||||
<p className='text-sm'>
|
||||
Agentic tracks all tool calls for usage-based billing and
|
||||
analytics at a fine-grained level, so you can drill in and deeply
|
||||
understand how your customers are using your product.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className='flex flex-col gap-2'>
|
||||
<h4 className='text-center text-balance text-lg font-heading'>
|
||||
Versioning
|
||||
</h4>
|
||||
|
||||
<p className='text-sm'>
|
||||
Just like Vercel, Agentic uses immutable deployments, so every
|
||||
time you make a change to your product's config, pricing, or docs,
|
||||
a unique preview deployment is created for that change. This
|
||||
enables instant rollbacks if there are problems with a deployment.
|
||||
Publishing deployments publicly uses semantic versioning (
|
||||
<em>semver</em>), so your customers can choose how to handle
|
||||
breaking changes.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className='flex flex-col gap-2'>
|
||||
<h4 className='text-center text-balance text-lg font-heading'>
|
||||
That's just the start
|
||||
</h4>
|
||||
|
||||
<p className='text-sm'>
|
||||
<Link href={docsUrl} className='link'>
|
||||
Check out our docs
|
||||
</Link>{' '}
|
||||
for more details on Agentic's MCP API gateway.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Marketplace section */}
|
||||
{/* <section className='flex flex-col gap-8 mb-16'>
|
||||
<h2 className='text-center text-balance leading-snug md:leading-none text-3xl font-heading'>
|
||||
MCP Marketplace
|
||||
MCP Tools that just work
|
||||
</h2>
|
||||
|
||||
<p>
|
||||
<i>Coming soon...</i>
|
||||
</p>
|
||||
</section> */}
|
||||
</section>
|
||||
|
||||
{/* Open source section */}
|
||||
<section className='flex flex-col items-center gap-8 max-w-2xl text-center mb-16'>
|
||||
|
@ -245,10 +95,10 @@ export default function TheBestDamnLandingPageEver() {
|
|||
{/* CTA section */}
|
||||
<section className='flex flex-col gap-12 mb-16'>
|
||||
<h2 className='text-center text-balance leading-snug md:leading-none text-3xl font-heading'>
|
||||
Deploy Your MCP Today
|
||||
Level up your AI Agents with the best tools
|
||||
</h2>
|
||||
|
||||
<SupplySideCTA variant='github-2' />
|
||||
<DemandSideCTA />
|
||||
</section>
|
||||
</>
|
||||
)
|
||||
|
|
|
@ -8,11 +8,15 @@ export function DemandSideCTA() {
|
|||
return (
|
||||
<div className='flex justify-center items-center gap-8'>
|
||||
<HeroButton asChild className='h-full'>
|
||||
<Link href='/marketplace'>MCP Marketplace</Link>
|
||||
<Link href='/marketplace' className='font-mono'>
|
||||
gotoTools();
|
||||
</Link>
|
||||
</HeroButton>
|
||||
|
||||
<Button variant='outline' asChild className='h-full'>
|
||||
<Link href={docsMarketplaceUrl}>Check out the docs</Link>
|
||||
<Link href={docsMarketplaceUrl} className='font-mono'>
|
||||
readDocs();
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
)
|
||||
|
|
|
@ -0,0 +1,140 @@
|
|||
'use client'
|
||||
|
||||
import { Physics, useSphere } from '@react-three/cannon'
|
||||
import { Environment, useTexture } from '@react-three/drei'
|
||||
import { Canvas, useFrame, useThree } from '@react-three/fiber'
|
||||
import {
|
||||
Bloom,
|
||||
EffectComposer,
|
||||
// N8AO,
|
||||
SMAA,
|
||||
SSAO
|
||||
} from '@react-three/postprocessing'
|
||||
import * as THREE from 'three'
|
||||
|
||||
const rfs = THREE.MathUtils.randFloatSpread
|
||||
const sphereGeometry = new THREE.SphereGeometry(1, 32, 32)
|
||||
const baubleMaterial = new THREE.MeshStandardMaterial({
|
||||
color: 'white',
|
||||
roughness: 0,
|
||||
envMapIntensity: 1
|
||||
})
|
||||
|
||||
export function HeroSimulation2({ className }: { className?: string }) {
|
||||
return (
|
||||
<Canvas
|
||||
shadows
|
||||
gl={{ antialias: false }}
|
||||
dpr={[1, 1.5]}
|
||||
camera={{ position: [0, 0, 20], fov: 35, near: 1, far: 40 }}
|
||||
className={className}
|
||||
>
|
||||
<ambientLight intensity={0.5} />
|
||||
|
||||
<color attach='background' args={['#dfdfdf']} />
|
||||
|
||||
<spotLight
|
||||
intensity={1}
|
||||
angle={0.2}
|
||||
penumbra={1}
|
||||
position={[30, 30, 30]}
|
||||
castShadow
|
||||
shadow-mapSize={[512, 512]}
|
||||
/>
|
||||
|
||||
<Physics gravity={[0, 2, 0]} iterations={10}>
|
||||
<Pointer />
|
||||
<Clump />
|
||||
</Physics>
|
||||
|
||||
<Environment files='/adamsbridge.hdr' />
|
||||
|
||||
<EffectComposer enableNormalPass={true} multisampling={0}>
|
||||
<SSAO />
|
||||
{/* <N8AO
|
||||
halfRes
|
||||
color='black'
|
||||
aoRadius={2}
|
||||
intensity={1}
|
||||
aoSamples={6}
|
||||
denoiseSamples={4}
|
||||
/> */}
|
||||
|
||||
<Bloom mipmapBlur levels={7} intensity={0.3} />
|
||||
|
||||
<SMAA />
|
||||
</EffectComposer>
|
||||
</Canvas>
|
||||
)
|
||||
}
|
||||
|
||||
function Clump({
|
||||
mat = new THREE.Matrix4(),
|
||||
vec = new THREE.Vector3(),
|
||||
numBalls = 64
|
||||
}) {
|
||||
const texture = useTexture('/mcp.png')
|
||||
const [ref, api] = useSphere(() => ({
|
||||
args: [1],
|
||||
mass: 1,
|
||||
angularDamping: 0.1,
|
||||
linearDamping: 0.65,
|
||||
position: [rfs(20), rfs(20), rfs(20)]
|
||||
}))
|
||||
|
||||
useFrame((_state, _delta) => {
|
||||
for (let i = 0; i < numBalls; i++) {
|
||||
// Get current whereabouts of the instanced sphere
|
||||
;(ref.current as any).getMatrixAt(i, mat)
|
||||
// ref.current.children[i]!.getM(i, mat)
|
||||
|
||||
// Normalize the position and multiply by a negative force.
|
||||
// This is enough to drive it towards the center-point.
|
||||
api
|
||||
.at(i)
|
||||
?.applyForce(
|
||||
vec
|
||||
.setFromMatrixPosition(mat)
|
||||
.normalize()
|
||||
.multiplyScalar(-40)
|
||||
.toArray(),
|
||||
[0, 0, 0]
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
return (
|
||||
<instancedMesh
|
||||
ref={ref}
|
||||
castShadow
|
||||
receiveShadow
|
||||
args={[sphereGeometry, baubleMaterial, numBalls]}
|
||||
material-map={texture}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function Pointer() {
|
||||
const viewport = useThree((state) => state.viewport)
|
||||
const [ref, api] = useSphere(() => ({
|
||||
type: 'Kinematic',
|
||||
args: [3],
|
||||
position: [0, 0, 0]
|
||||
}))
|
||||
|
||||
useFrame((state) =>
|
||||
api.position.set(
|
||||
(state.pointer.x * viewport.width) / 2,
|
||||
(state.pointer.y * viewport.height) / 2,
|
||||
0
|
||||
)
|
||||
)
|
||||
|
||||
return (
|
||||
<mesh ref={ref} scale={0.2}>
|
||||
<sphereGeometry />
|
||||
<meshBasicMaterial color={[4, 4, 4]} toneMapped={false} />
|
||||
<pointLight intensity={8} distance={10} />
|
||||
</mesh>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,146 @@
|
|||
'use client'
|
||||
|
||||
import {
|
||||
MarchingCube,
|
||||
MarchingCubes,
|
||||
MeshTransmissionMaterial,
|
||||
RenderTexture,
|
||||
Text
|
||||
} from '@react-three/drei'
|
||||
import { Canvas, useFrame } from '@react-three/fiber'
|
||||
import { BallCollider, Physics, RigidBody } from '@react-three/rapier'
|
||||
import { useRef } from 'react'
|
||||
import { suspend } from 'suspend-react'
|
||||
import * as THREE from 'three'
|
||||
|
||||
const inter = import('@pmndrs/assets/fonts/inter_regular.woff')
|
||||
|
||||
// https://codesandbox.io/p/sandbox/metaballs-forked-g7xjjq?file=%2Fsrc%2FApp.js
|
||||
|
||||
function MetaBall({
|
||||
float = false,
|
||||
strength = 0.5,
|
||||
color,
|
||||
vec = new THREE.Vector3(),
|
||||
...props
|
||||
}: {
|
||||
float?: boolean
|
||||
strength?: number
|
||||
color?: string
|
||||
vec?: THREE.Vector3
|
||||
} & Parameters<typeof RigidBody>[0]) {
|
||||
const api = useRef<any>(null)
|
||||
|
||||
useFrame((_state, delta) => {
|
||||
if (float) {
|
||||
delta = Math.min(delta, 0.1)
|
||||
api.current?.applyImpulse(
|
||||
vec
|
||||
//.set(-state.pointer.x, -state.pointer.y, 0)
|
||||
.copy(api.current.translation())
|
||||
.normalize()
|
||||
.multiplyScalar(delta * -0.2)
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
return (
|
||||
<RigidBody
|
||||
ref={api}
|
||||
colliders={false}
|
||||
restitution={0.6}
|
||||
linearDamping={4}
|
||||
angularDamping={4}
|
||||
{...props}
|
||||
>
|
||||
<MarchingCube
|
||||
strength={strength}
|
||||
subtract={6}
|
||||
color={new THREE.Color(color)}
|
||||
/>
|
||||
|
||||
<BallCollider args={[0.1]} />
|
||||
</RigidBody>
|
||||
)
|
||||
}
|
||||
|
||||
function Pointer({ vec = new THREE.Vector3() }) {
|
||||
const ref = useRef<any>(null)
|
||||
|
||||
useFrame(({ pointer, viewport }) => {
|
||||
const { width, height } = viewport.getCurrentViewport()
|
||||
vec.set((pointer.x * width) / 2, (pointer.y * height) / 2, 0)
|
||||
ref.current?.setNextKinematicTranslation(vec)
|
||||
})
|
||||
|
||||
return (
|
||||
<RigidBody type='kinematicPosition' colliders={false} ref={ref}>
|
||||
<BallCollider args={[0.3]} />
|
||||
</RigidBody>
|
||||
)
|
||||
}
|
||||
|
||||
export function HeroSimulation({ className }: { className?: string }) {
|
||||
return (
|
||||
<Canvas
|
||||
dpr={[1, 1.5]}
|
||||
orthographic
|
||||
camera={{ position: [0, 0, 5], zoom: 300 }}
|
||||
className={className}
|
||||
>
|
||||
<color attach='background' args={['blue']} />
|
||||
|
||||
<ambientLight intensity={1} />
|
||||
|
||||
<Physics gravity={[0, -5, 0]}>
|
||||
<MarchingCubes
|
||||
resolution={40}
|
||||
maxPolyCount={10_000}
|
||||
enableUvs={false}
|
||||
enableColors
|
||||
>
|
||||
<MeshTransmissionMaterial
|
||||
thickness={0.4}
|
||||
anisotropicBlur={0.1}
|
||||
chromaticAberration={0.1}
|
||||
vertexColors
|
||||
roughness={0}
|
||||
>
|
||||
<RenderTexture attach='buffer'>
|
||||
<color attach='background' args={[new THREE.Color(2, 2, 2)]} />
|
||||
|
||||
<Text
|
||||
scale={0.25}
|
||||
fontSize={1}
|
||||
position={[0, 0, -5]}
|
||||
letterSpacing={-0.025}
|
||||
outlineWidth={0.03}
|
||||
font={(suspend(inter) as any).default}
|
||||
color='black'
|
||||
>
|
||||
MCP
|
||||
</Text>
|
||||
</RenderTexture>
|
||||
</MeshTransmissionMaterial>
|
||||
|
||||
{Array.from({ length: 10 }, (_, index) => (
|
||||
<MetaBall
|
||||
float
|
||||
strength={1}
|
||||
key={'1' + index}
|
||||
color='white'
|
||||
position={[Math.random() * 0.5, Math.random() * 0.5, 0]}
|
||||
/>
|
||||
))}
|
||||
|
||||
<Pointer />
|
||||
</MarchingCubes>
|
||||
</Physics>
|
||||
|
||||
{/* <Environment
|
||||
files="https://dl.polyhaven.org/file/ph-assets/HDRIs/hdr/1k/industrial_workshop_foundry_1k.hdr"
|
||||
environmentIntensity={0.5}
|
||||
/> */}
|
||||
</Canvas>
|
||||
)
|
||||
}
|
895
pnpm-lock.yaml
895
pnpm-lock.yaml
Plik diff jest za duży
Load Diff
Ładowanie…
Reference in New Issue