mirror of
https://github.com/katanemo/plano.git
synced 2026-07-05 15:52:12 +02:00
format(www)
This commit is contained in:
parent
a825ce9add
commit
64d45a7a00
27 changed files with 257 additions and 314 deletions
|
|
@ -1,101 +0,0 @@
|
||||||
# ArchGW Monorepo
|
|
||||||
|
|
||||||
This is a Turborepo monorepo containing the Next.js applications and shared packages.
|
|
||||||
|
|
||||||
## Structure
|
|
||||||
|
|
||||||
```
|
|
||||||
.
|
|
||||||
├── apps/
|
|
||||||
│ ├── www/ # Marketing website
|
|
||||||
│ └── docs/ # Documentation site
|
|
||||||
├── packages/
|
|
||||||
│ ├── ui/ # Shared UI components (Navbar, Footer, Logo, etc.)
|
|
||||||
│ ├── shared-styles/ # Shared CSS and Tailwind configuration
|
|
||||||
│ ├── tailwind-config/ # Tailwind configuration
|
|
||||||
│ └── tsconfig/ # Shared TypeScript configurations
|
|
||||||
└── turbo.json # Turborepo configuration
|
|
||||||
```
|
|
||||||
|
|
||||||
## Getting Started
|
|
||||||
|
|
||||||
### Install Dependencies
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm install
|
|
||||||
```
|
|
||||||
|
|
||||||
### Development
|
|
||||||
|
|
||||||
Run all apps in development mode:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm run dev
|
|
||||||
```
|
|
||||||
|
|
||||||
Or run specific apps:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Marketing website (port 3000)
|
|
||||||
cd apps/www && npm run dev
|
|
||||||
|
|
||||||
# Documentation (port 3001)
|
|
||||||
cd apps/docs && npm run dev
|
|
||||||
```
|
|
||||||
|
|
||||||
### Build
|
|
||||||
|
|
||||||
Build all apps:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm run build
|
|
||||||
```
|
|
||||||
|
|
||||||
### Lint & Type Check
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm run lint
|
|
||||||
npm run typecheck
|
|
||||||
```
|
|
||||||
|
|
||||||
## Shared Packages
|
|
||||||
|
|
||||||
### @archgw/ui
|
|
||||||
|
|
||||||
Shared React components including:
|
|
||||||
- `Navbar` - Navigation bar component
|
|
||||||
- `Footer` - Footer component
|
|
||||||
- `Logo` - Logo component
|
|
||||||
- UI components (Button, Dialog, etc.)
|
|
||||||
|
|
||||||
### @archgw/shared-styles
|
|
||||||
|
|
||||||
Shared CSS styles including:
|
|
||||||
- Tailwind CSS configuration
|
|
||||||
- Font definitions (IBM Plex Sans, JetBrains Mono)
|
|
||||||
- CSS variables for theming
|
|
||||||
|
|
||||||
### @archgw/tailwind-config
|
|
||||||
|
|
||||||
Shared Tailwind CSS configuration.
|
|
||||||
|
|
||||||
### @archgw/tsconfig
|
|
||||||
|
|
||||||
Shared TypeScript configurations:
|
|
||||||
- `base.json` - Base TypeScript config
|
|
||||||
- `nextjs.json` - Next.js specific config
|
|
||||||
|
|
||||||
## Design System
|
|
||||||
|
|
||||||
Both apps share the same design system:
|
|
||||||
- Same fonts (IBM Plex Sans, JetBrains Mono)
|
|
||||||
- Same color palette
|
|
||||||
- Same components (Navbar, Footer)
|
|
||||||
- Same Tailwind configuration
|
|
||||||
|
|
||||||
## Notes
|
|
||||||
|
|
||||||
- Fonts are stored in each app's `public/fonts/` directory
|
|
||||||
- Both apps use the same shared components and styles
|
|
||||||
- The monorepo uses npm workspaces and Turborepo for build orchestration
|
|
||||||
|
|
||||||
|
|
@ -19,7 +19,7 @@ const nextConfig: NextConfig = {
|
||||||
"node_modules",
|
"node_modules",
|
||||||
"../../node_modules",
|
"../../node_modules",
|
||||||
];
|
];
|
||||||
|
|
||||||
if (!isServer) {
|
if (!isServer) {
|
||||||
config.resolve.fallback = {
|
config.resolve.fallback = {
|
||||||
...config.resolve.fallback,
|
...config.resolve.fallback,
|
||||||
|
|
|
||||||
|
|
@ -16,4 +16,4 @@ export default defineConfig({
|
||||||
schema: {
|
schema: {
|
||||||
types: schemaTypes,
|
types: schemaTypes,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,9 @@ export const runtime = "edge";
|
||||||
function loadFont(fileName: string, baseUrl: string) {
|
function loadFont(fileName: string, baseUrl: string) {
|
||||||
return fetch(new URL(`/fonts/${fileName}`, baseUrl)).then((res) => {
|
return fetch(new URL(`/fonts/${fileName}`, baseUrl)).then((res) => {
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
throw new Error(`Failed to fetch font ${fileName}: ${res.status} ${res.statusText}`);
|
throw new Error(
|
||||||
|
`Failed to fetch font ${fileName}: ${res.status} ${res.statusText}`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return res.arrayBuffer();
|
return res.arrayBuffer();
|
||||||
});
|
});
|
||||||
|
|
@ -63,16 +65,20 @@ export async function GET(
|
||||||
// Load fonts with error handling
|
// Load fonts with error handling
|
||||||
let fontData;
|
let fontData;
|
||||||
try {
|
try {
|
||||||
const [ibmPlexSans, jetbrainsMonoRegular, jetbrainsMonoMedium, jetbrainsMonoBold] =
|
const [
|
||||||
await Promise.all([
|
ibmPlexSans,
|
||||||
loadFont("IBMPlexSans-VariableFont_wdth,wght.otf", fontBaseUrl),
|
jetbrainsMonoRegular,
|
||||||
loadFont("JetBrainsMono-Regular.otf", fontBaseUrl),
|
jetbrainsMonoMedium,
|
||||||
loadFont("JetBrainsMono-Medium.otf", fontBaseUrl),
|
jetbrainsMonoBold,
|
||||||
loadFont("jetbrains-mono-bold.otf", fontBaseUrl),
|
] = await Promise.all([
|
||||||
]).catch((error: Error) => {
|
loadFont("IBMPlexSans-VariableFont_wdth,wght.otf", fontBaseUrl),
|
||||||
console.error("Error loading fonts:", error);
|
loadFont("JetBrainsMono-Regular.otf", fontBaseUrl),
|
||||||
throw new Error(`Failed to load fonts: ${error.message}`);
|
loadFont("JetBrainsMono-Medium.otf", fontBaseUrl),
|
||||||
});
|
loadFont("jetbrains-mono-bold.otf", fontBaseUrl),
|
||||||
|
]).catch((error: Error) => {
|
||||||
|
console.error("Error loading fonts:", error);
|
||||||
|
throw new Error(`Failed to load fonts: ${error.message}`);
|
||||||
|
});
|
||||||
|
|
||||||
fontData = {
|
fontData = {
|
||||||
ibmPlexSans,
|
ibmPlexSans,
|
||||||
|
|
@ -81,7 +87,8 @@ export async function GET(
|
||||||
jetbrainsMonoBold,
|
jetbrainsMonoBold,
|
||||||
};
|
};
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
const errorMessage =
|
||||||
|
error instanceof Error ? error.message : "Unknown error";
|
||||||
console.error("Font loading error:", errorMessage);
|
console.error("Font loading error:", errorMessage);
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
|
|
@ -97,7 +104,9 @@ export async function GET(
|
||||||
const post = await getBlogPost(slug);
|
const post = await getBlogPost(slug);
|
||||||
|
|
||||||
if (!post) {
|
if (!post) {
|
||||||
return new Response(JSON.stringify({ error: "Post not found" }), { status: 404 });
|
return new Response(JSON.stringify({ error: "Post not found" }), {
|
||||||
|
status: 404,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get author image URL if available
|
// Get author image URL if available
|
||||||
|
|
@ -114,8 +123,7 @@ export async function GET(
|
||||||
: request.nextUrl.origin);
|
: request.nextUrl.origin);
|
||||||
const logoUrl = `${baseUrl}/Logomark.png`;
|
const logoUrl = `${baseUrl}/Logomark.png`;
|
||||||
|
|
||||||
return new ImageResponse(
|
return new ImageResponse(
|
||||||
(
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
background: "linear-gradient(to top right, #ffffff, #dcdfff)",
|
background: "linear-gradient(to top right, #ffffff, #dcdfff)",
|
||||||
|
|
@ -259,53 +267,53 @@ export async function GET(
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>,
|
||||||
),
|
{
|
||||||
{
|
width: 1200,
|
||||||
width: 1200,
|
height: 630,
|
||||||
height: 630,
|
fonts: [
|
||||||
fonts: [
|
{
|
||||||
{
|
name: "IBM Plex Sans Regular",
|
||||||
name: "IBM Plex Sans Regular",
|
data: fontData.ibmPlexSans,
|
||||||
data: fontData.ibmPlexSans,
|
style: "normal",
|
||||||
style: "normal",
|
weight: 400,
|
||||||
weight: 400,
|
},
|
||||||
},
|
{
|
||||||
{
|
name: "IBM Plex Sans Medium",
|
||||||
name: "IBM Plex Sans Medium",
|
data: fontData.ibmPlexSans,
|
||||||
data: fontData.ibmPlexSans,
|
style: "normal",
|
||||||
style: "normal",
|
weight: 500,
|
||||||
weight: 500,
|
},
|
||||||
},
|
{
|
||||||
{
|
name: "IBM Plex Sans Bold",
|
||||||
name: "IBM Plex Sans Bold",
|
data: fontData.ibmPlexSans,
|
||||||
data: fontData.ibmPlexSans,
|
style: "normal",
|
||||||
style: "normal",
|
weight: 700,
|
||||||
weight: 700,
|
},
|
||||||
},
|
{
|
||||||
{
|
name: "JetBrains Mono Regular",
|
||||||
name: "JetBrains Mono Regular",
|
data: fontData.jetbrainsMonoRegular,
|
||||||
data: fontData.jetbrainsMonoRegular,
|
style: "normal",
|
||||||
style: "normal",
|
weight: 400,
|
||||||
weight: 400,
|
},
|
||||||
},
|
{
|
||||||
{
|
name: "JetBrains Mono Medium",
|
||||||
name: "JetBrains Mono Medium",
|
data: fontData.jetbrainsMonoMedium,
|
||||||
data: fontData.jetbrainsMonoMedium,
|
style: "normal",
|
||||||
style: "normal",
|
weight: 500,
|
||||||
weight: 500,
|
},
|
||||||
},
|
{
|
||||||
{
|
name: "JetBrains Mono Bold",
|
||||||
name: "JetBrains Mono Bold",
|
data: fontData.jetbrainsMonoBold,
|
||||||
data: fontData.jetbrainsMonoBold,
|
style: "normal",
|
||||||
style: "normal",
|
weight: 600,
|
||||||
weight: 600,
|
},
|
||||||
},
|
],
|
||||||
],
|
},
|
||||||
},
|
);
|
||||||
);
|
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
const errorMessage =
|
||||||
|
error instanceof Error ? error.message : "Unknown error";
|
||||||
console.error("Error generating image response:", error);
|
console.error("Error generating image response:", error);
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
|
|
@ -316,4 +324,3 @@ export async function GET(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ export async function generateMetadata({
|
||||||
// Get baseUrl - use NEXT_PUBLIC_APP_URL if set, otherwise construct from VERCEL_URL
|
// Get baseUrl - use NEXT_PUBLIC_APP_URL if set, otherwise construct from VERCEL_URL
|
||||||
// Restrict to allowed hosts: localhost:3000, archgw-tau.vercel.app, or plano.katanemo.com
|
// Restrict to allowed hosts: localhost:3000, archgw-tau.vercel.app, or plano.katanemo.com
|
||||||
let baseUrl = "http://localhost:3000";
|
let baseUrl = "http://localhost:3000";
|
||||||
|
|
||||||
if (process.env.NEXT_PUBLIC_APP_URL) {
|
if (process.env.NEXT_PUBLIC_APP_URL) {
|
||||||
const url = process.env.NEXT_PUBLIC_APP_URL;
|
const url = process.env.NEXT_PUBLIC_APP_URL;
|
||||||
if (
|
if (
|
||||||
|
|
@ -118,4 +118,3 @@ interface LayoutProps {
|
||||||
export default async function Layout({ children, params }: LayoutProps) {
|
export default async function Layout({ children, params }: LayoutProps) {
|
||||||
return <>{children}</>;
|
return <>{children}</>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,4 +33,3 @@ export default function NotFound() {
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -204,4 +204,3 @@ export default async function BlogPostPage({
|
||||||
</article>
|
</article>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -117,4 +117,3 @@ export default async function BlogPage() {
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,15 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { ResearchHero, ResearchGrid, ResearchTimeline, ResearchCTA, ResearchCapabilities, ResearchBenchmarks, ResearchFamily } from "@/components/research";
|
import {
|
||||||
|
ResearchHero,
|
||||||
|
ResearchGrid,
|
||||||
|
ResearchTimeline,
|
||||||
|
ResearchCTA,
|
||||||
|
ResearchCapabilities,
|
||||||
|
ResearchBenchmarks,
|
||||||
|
ResearchFamily,
|
||||||
|
} from "@/components/research";
|
||||||
import { UnlockPotentialSection } from "@/components/UnlockPotentialSection";
|
import { UnlockPotentialSection } from "@/components/UnlockPotentialSection";
|
||||||
|
|
||||||
export default function ResearchPage() {
|
export default function ResearchPage() {
|
||||||
|
|
|
||||||
|
|
@ -9,4 +9,3 @@ export default function StudioLayout({
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -85,4 +85,3 @@ export function BlogCard({ post, index = 0 }: BlogCardProps) {
|
||||||
</motion.div>
|
</motion.div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,4 +23,3 @@ export function BlogHeader() {
|
||||||
</motion.section>
|
</motion.section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,7 @@
|
||||||
export function BlogSectionHeader() {
|
export function BlogSectionHeader() {
|
||||||
return (
|
return (
|
||||||
<h2 className="text-2xl sm:text-3xl lg:text-4xl font-normal leading-tight tracking-tighter text-black mb-12">
|
<h2 className="text-2xl sm:text-3xl lg:text-4xl font-normal leading-tight tracking-tighter text-black mb-12">
|
||||||
<span className="font-sans">
|
<span className="font-sans">The latest and greatest from our blog.</span>
|
||||||
The latest and greatest from our blog.
|
|
||||||
</span>
|
|
||||||
</h2>
|
</h2>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,7 @@
|
||||||
import { usePathname } from "next/navigation";
|
import { usePathname } from "next/navigation";
|
||||||
import { Navbar, Footer } from "@katanemo/ui";
|
import { Navbar, Footer } from "@katanemo/ui";
|
||||||
|
|
||||||
export function ConditionalLayout({
|
export function ConditionalLayout({ children }: { children: React.ReactNode }) {
|
||||||
children,
|
|
||||||
}: {
|
|
||||||
children: React.ReactNode;
|
|
||||||
}) {
|
|
||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
const isStudio = pathname?.startsWith("/studio");
|
const isStudio = pathname?.startsWith("/studio");
|
||||||
|
|
||||||
|
|
@ -23,4 +19,3 @@ export function ConditionalLayout({
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -115,4 +115,3 @@ export function FeaturedBlogCard({ post }: FeaturedBlogCardProps) {
|
||||||
</motion.div>
|
</motion.div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,9 +44,8 @@ export function Hero() {
|
||||||
{/* Subheading with CTA Buttons */}
|
{/* Subheading with CTA Buttons */}
|
||||||
<div className="max-w-7xl relative z-10">
|
<div className="max-w-7xl relative z-10">
|
||||||
<p className="text-base sm:text-lg md:text-xl lg:text-[22px] font-sans font-[400] tracking-[-1.0px] sm:tracking-[-1.22px]! text-black max-w-76 sm:max-w-2xl mb-6">
|
<p className="text-base sm:text-lg md:text-xl lg:text-[22px] font-sans font-[400] tracking-[-1.0px] sm:tracking-[-1.22px]! text-black max-w-76 sm:max-w-2xl mb-6">
|
||||||
Build agents faster, and deliver them reliably to production -
|
Build agents faster, and deliver them reliably to production - by
|
||||||
by offloading the critical plumbing work to Plano.
|
offloading the critical plumbing work to Plano.
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{/* CTA Buttons */}
|
{/* CTA Buttons */}
|
||||||
|
|
|
||||||
|
|
@ -150,7 +150,9 @@ export function IdeaToAgentSection() {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Button asChild className="mt-6 sm:mt-8 w-full sm:w-auto">
|
<Button asChild className="mt-6 sm:mt-8 w-full sm:w-auto">
|
||||||
<Link href={carouselData[currentSlide].link}>Learn more</Link>
|
<Link href={carouselData[currentSlide].link}>
|
||||||
|
Learn more
|
||||||
|
</Link>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -20,15 +20,18 @@ export function IntroSection() {
|
||||||
{/* Body Text */}
|
{/* Body Text */}
|
||||||
<div className="text-white text-sm sm:text-base lg:text-lg max-w-[713px]">
|
<div className="text-white text-sm sm:text-base lg:text-lg max-w-[713px]">
|
||||||
<p className="mb-0">
|
<p className="mb-0">
|
||||||
Plano is a models-native proxy and dataplane for agents that handles
|
Plano is a models-native proxy and dataplane for agents that
|
||||||
critical plumbing work in AI - agent routing and orchestration, rich agentic
|
handles critical plumbing work in AI - agent routing and
|
||||||
traces, guardrail hooks, and smart model routing APIs for LLMs. Use any
|
orchestration, rich agentic traces, guardrail hooks, and smart
|
||||||
language, AI framework, and deliver agents to productions quickly with Plano.
|
model routing APIs for LLMs. Use any language, AI framework, and
|
||||||
|
deliver agents to productions quickly with Plano.
|
||||||
</p>
|
</p>
|
||||||
<p className="mb-0 mt-4">
|
<p className="mb-0 mt-4">
|
||||||
Developers can focus more on core product logic of agents.
|
Developers can focus more on core product logic of agents.
|
||||||
Product teams can accelerate feedback loops for reinforcement learning.
|
Product teams can accelerate feedback loops for reinforcement
|
||||||
Engineering teams can standardize policies and access controls across every agent and LLM for safer, more reliable scaling.
|
learning. Engineering teams can standardize policies and access
|
||||||
|
controls across every agent and LLM for safer, more reliable
|
||||||
|
scaling.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -34,17 +34,17 @@ export function LogoCloud() {
|
||||||
const isTMobile = index === 1; // T-Mobile is before HP
|
const isTMobile = index === 1; // T-Mobile is before HP
|
||||||
const isHP = index === 2; // HP is in center
|
const isHP = index === 2; // HP is in center
|
||||||
const isSanDisk = index === 3; // SanDisk is after HP
|
const isSanDisk = index === 3; // SanDisk is after HP
|
||||||
|
|
||||||
// Custom spacing for logos around HP on large screens
|
// Custom spacing for logos around HP on large screens
|
||||||
let spacingClass = 'lg:mx-6 xl:mx-8'; // Default spacing
|
let spacingClass = "lg:mx-6 xl:mx-8"; // Default spacing
|
||||||
if (isTMobile) {
|
if (isTMobile) {
|
||||||
spacingClass = 'lg:mr-3 xl:mr-4 lg:ml-6 xl:ml-8'; // Smaller gap to HP
|
spacingClass = "lg:mr-3 xl:mr-4 lg:ml-6 xl:ml-8"; // Smaller gap to HP
|
||||||
} else if (isHP) {
|
} else if (isHP) {
|
||||||
spacingClass = 'lg:mx-3 xl:mx-4'; // Smaller gaps on both sides
|
spacingClass = "lg:mx-3 xl:mx-4"; // Smaller gaps on both sides
|
||||||
} else if (isSanDisk) {
|
} else if (isSanDisk) {
|
||||||
spacingClass = 'lg:ml-3 xl:ml-4 lg:mr-6 xl:mr-8'; // Smaller gap from HP
|
spacingClass = "lg:ml-3 xl:ml-4 lg:mr-6 xl:mr-8"; // Smaller gap from HP
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={logo.name}
|
key={logo.name}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ const squares = [
|
||||||
{ x: 3, y: 15, color: "#ABB2FA", col: 0, row: 4 },
|
{ x: 3, y: 15, color: "#ABB2FA", col: 0, row: 4 },
|
||||||
{ x: 3, y: 18, color: "#ABB2FA", col: 0, row: 5 },
|
{ x: 3, y: 18, color: "#ABB2FA", col: 0, row: 5 },
|
||||||
{ x: 3, y: 21, color: "#969FF4", col: 0, row: 6 },
|
{ x: 3, y: 21, color: "#969FF4", col: 0, row: 6 },
|
||||||
|
|
||||||
// Column 2 (x=6)
|
// Column 2 (x=6)
|
||||||
{ x: 6, y: 3, color: "#B0B7FF", col: 1, row: 0 },
|
{ x: 6, y: 3, color: "#B0B7FF", col: 1, row: 0 },
|
||||||
{ x: 6, y: 6, color: "#B0B7FF", col: 1, row: 1 },
|
{ x: 6, y: 6, color: "#B0B7FF", col: 1, row: 1 },
|
||||||
|
|
@ -22,7 +22,7 @@ const squares = [
|
||||||
{ x: 6, y: 15, color: "#ABB2FA", col: 1, row: 4 },
|
{ x: 6, y: 15, color: "#ABB2FA", col: 1, row: 4 },
|
||||||
{ x: 6, y: 18, color: "#969FF4", col: 1, row: 5 },
|
{ x: 6, y: 18, color: "#969FF4", col: 1, row: 5 },
|
||||||
{ x: 6, y: 21, color: "#969FF4", col: 1, row: 6 },
|
{ x: 6, y: 21, color: "#969FF4", col: 1, row: 6 },
|
||||||
|
|
||||||
// Column 3 (x=9)
|
// Column 3 (x=9)
|
||||||
{ x: 9, y: 3, color: "#B0B7FF", col: 2, row: 0 },
|
{ x: 9, y: 3, color: "#B0B7FF", col: 2, row: 0 },
|
||||||
{ x: 9, y: 6, color: "#ABB2FA", col: 2, row: 1 },
|
{ x: 9, y: 6, color: "#ABB2FA", col: 2, row: 1 },
|
||||||
|
|
@ -31,7 +31,7 @@ const squares = [
|
||||||
{ x: 9, y: 15, color: "#969FF4", col: 2, row: 4 },
|
{ x: 9, y: 15, color: "#969FF4", col: 2, row: 4 },
|
||||||
{ x: 9, y: 18, color: "#969FF4", col: 2, row: 5 },
|
{ x: 9, y: 18, color: "#969FF4", col: 2, row: 5 },
|
||||||
{ x: 9, y: 21, color: "#969FF4", col: 2, row: 6 },
|
{ x: 9, y: 21, color: "#969FF4", col: 2, row: 6 },
|
||||||
|
|
||||||
// Column 4 (x=12)
|
// Column 4 (x=12)
|
||||||
{ x: 12, y: 3, color: "#ABB2FA", col: 3, row: 0 },
|
{ x: 12, y: 3, color: "#ABB2FA", col: 3, row: 0 },
|
||||||
{ x: 12, y: 6, color: "#ABB2FA", col: 3, row: 1 },
|
{ x: 12, y: 6, color: "#ABB2FA", col: 3, row: 1 },
|
||||||
|
|
@ -40,7 +40,7 @@ const squares = [
|
||||||
{ x: 12, y: 15, color: "#969FF4", col: 3, row: 4 },
|
{ x: 12, y: 15, color: "#969FF4", col: 3, row: 4 },
|
||||||
{ x: 12, y: 18, color: "#969FF4", col: 3, row: 5 },
|
{ x: 12, y: 18, color: "#969FF4", col: 3, row: 5 },
|
||||||
{ x: 12, y: 21, color: "#969FF4", col: 3, row: 6 },
|
{ x: 12, y: 21, color: "#969FF4", col: 3, row: 6 },
|
||||||
|
|
||||||
// Column 5 (x=15)
|
// Column 5 (x=15)
|
||||||
{ x: 15, y: 3, color: "#ABB2FA", col: 4, row: 0 },
|
{ x: 15, y: 3, color: "#ABB2FA", col: 4, row: 0 },
|
||||||
{ x: 15, y: 6, color: "#ABB2FA", col: 4, row: 1 },
|
{ x: 15, y: 6, color: "#ABB2FA", col: 4, row: 1 },
|
||||||
|
|
@ -49,7 +49,7 @@ const squares = [
|
||||||
{ x: 15, y: 15, color: "#969FF4", col: 4, row: 4 },
|
{ x: 15, y: 15, color: "#969FF4", col: 4, row: 4 },
|
||||||
{ x: 15, y: 18, color: "#969FF4", col: 4, row: 5 },
|
{ x: 15, y: 18, color: "#969FF4", col: 4, row: 5 },
|
||||||
{ x: 15, y: 21, color: "#969FF4", col: 4, row: 6 },
|
{ x: 15, y: 21, color: "#969FF4", col: 4, row: 6 },
|
||||||
|
|
||||||
// Column 6 (x=18)
|
// Column 6 (x=18)
|
||||||
{ x: 18, y: 3, color: "#ABB2FA", col: 5, row: 0 },
|
{ x: 18, y: 3, color: "#ABB2FA", col: 5, row: 0 },
|
||||||
{ x: 18, y: 6, color: "#969FF4", col: 5, row: 1 },
|
{ x: 18, y: 6, color: "#969FF4", col: 5, row: 1 },
|
||||||
|
|
@ -58,7 +58,7 @@ const squares = [
|
||||||
{ x: 18, y: 15, color: "#969FF4", col: 5, row: 4 },
|
{ x: 18, y: 15, color: "#969FF4", col: 5, row: 4 },
|
||||||
{ x: 18, y: 18, color: "#969FF4", col: 5, row: 5 },
|
{ x: 18, y: 18, color: "#969FF4", col: 5, row: 5 },
|
||||||
{ x: 18, y: 21, color: "#969FF4", col: 5, row: 6 },
|
{ x: 18, y: 21, color: "#969FF4", col: 5, row: 6 },
|
||||||
|
|
||||||
// Column 7 (x=21)
|
// Column 7 (x=21)
|
||||||
{ x: 21, y: 3, color: "#969FF4", col: 6, row: 0 },
|
{ x: 21, y: 3, color: "#969FF4", col: 6, row: 0 },
|
||||||
{ x: 21, y: 6, color: "#969FF4", col: 6, row: 1 },
|
{ x: 21, y: 6, color: "#969FF4", col: 6, row: 1 },
|
||||||
|
|
@ -92,7 +92,7 @@ function getDeterministicValues(index: number) {
|
||||||
const seed4 = index * 0.4;
|
const seed4 = index * 0.4;
|
||||||
const seed5 = index * 0.5;
|
const seed5 = index * 0.5;
|
||||||
const seed6 = index * 0.6;
|
const seed6 = index * 0.6;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
duration: roundToPrecision(3 + seededRandom(seed1) * 3, 10), // 3-6 seconds
|
duration: roundToPrecision(3 + seededRandom(seed1) * 3, 10), // 3-6 seconds
|
||||||
peakOpacity: roundToPrecision(0.7 + seededRandom(seed2) * 0.3, 10),
|
peakOpacity: roundToPrecision(0.7 + seededRandom(seed2) * 0.3, 10),
|
||||||
|
|
@ -105,9 +105,9 @@ function getDeterministicValues(index: number) {
|
||||||
|
|
||||||
export function NetworkAnimation({ className }: NetworkAnimationProps) {
|
export function NetworkAnimation({ className }: NetworkAnimationProps) {
|
||||||
// Generate unique IDs for gradient and mask to avoid conflicts when multiple instances exist
|
// Generate unique IDs for gradient and mask to avoid conflicts when multiple instances exist
|
||||||
const gradientId = useId().replace(/:/g, '-');
|
const gradientId = useId().replace(/:/g, "-");
|
||||||
const maskId = useId().replace(/:/g, '-');
|
const maskId = useId().replace(/:/g, "-");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="absolute inset-0 pointer-events-none opacity-100">
|
<div className="absolute inset-0 pointer-events-none opacity-100">
|
||||||
<motion.div
|
<motion.div
|
||||||
|
|
@ -143,55 +143,61 @@ export function NetworkAnimation({ className }: NetworkAnimationProps) {
|
||||||
<rect width="26" height="26" fill={`url(#${gradientId})`} />
|
<rect width="26" height="26" fill={`url(#${gradientId})`} />
|
||||||
</mask>
|
</mask>
|
||||||
</defs>
|
</defs>
|
||||||
|
|
||||||
<g mask={`url(#${maskId})`}>
|
<g mask={`url(#${maskId})`}>
|
||||||
{/* Outer border */}
|
{/* Outer border */}
|
||||||
<rect width="26" height="26" fill="#7780D9" />
|
<rect width="26" height="26" fill="#7780D9" />
|
||||||
|
|
||||||
{/* Inner background */}
|
{/* Inner background */}
|
||||||
<rect x="2" y="2" width="22" height="22" fill="#B9BFFF" />
|
<rect x="2" y="2" width="22" height="22" fill="#B9BFFF" />
|
||||||
|
|
||||||
{/* Animated squares with wave effect */}
|
{/* Animated squares with wave effect */}
|
||||||
{squares.map((square, index) => {
|
{squares.map((square, index) => {
|
||||||
// Use deterministic values based on index for SSR/client consistency
|
// Use deterministic values based on index for SSR/client consistency
|
||||||
const { duration, peakOpacity, baseOpacity, midOpacity, baseBrightness, peakBrightness } =
|
const {
|
||||||
getDeterministicValues(index);
|
duration,
|
||||||
|
peakOpacity,
|
||||||
return (
|
baseOpacity,
|
||||||
<motion.path
|
midOpacity,
|
||||||
key={`square-${index}`}
|
baseBrightness,
|
||||||
d={`M${square.x} ${square.y}H${square.x + 2}V${square.y + 2}H${square.x}V${square.y}Z`}
|
peakBrightness,
|
||||||
fill={square.color}
|
} = getDeterministicValues(index);
|
||||||
initial={{
|
|
||||||
opacity: roundToPrecision(baseOpacity, 10),
|
return (
|
||||||
filter: `brightness(${roundToPrecision(baseBrightness, 10)})`,
|
<motion.path
|
||||||
}}
|
key={`square-${index}`}
|
||||||
animate={{
|
d={`M${square.x} ${square.y}H${square.x + 2}V${square.y + 2}H${square.x}V${square.y}Z`}
|
||||||
opacity: [
|
fill={square.color}
|
||||||
roundToPrecision(baseOpacity, 10),
|
initial={{
|
||||||
roundToPrecision(midOpacity, 10),
|
opacity: roundToPrecision(baseOpacity, 10),
|
||||||
roundToPrecision(peakOpacity, 10),
|
filter: `brightness(${roundToPrecision(baseBrightness, 10)})`,
|
||||||
roundToPrecision(midOpacity, 10),
|
}}
|
||||||
roundToPrecision(baseOpacity, 10),
|
animate={{
|
||||||
],
|
opacity: [
|
||||||
filter: [
|
roundToPrecision(baseOpacity, 10),
|
||||||
`brightness(${roundToPrecision(baseBrightness, 10)})`,
|
roundToPrecision(midOpacity, 10),
|
||||||
`brightness(${roundToPrecision((baseBrightness + peakBrightness) / 2, 10)})`,
|
roundToPrecision(peakOpacity, 10),
|
||||||
`brightness(${roundToPrecision(peakBrightness, 10)})`,
|
roundToPrecision(midOpacity, 10),
|
||||||
`brightness(${roundToPrecision((baseBrightness + peakBrightness) / 2, 10)})`,
|
roundToPrecision(baseOpacity, 10),
|
||||||
`brightness(${roundToPrecision(baseBrightness, 10)})`,
|
],
|
||||||
],
|
filter: [
|
||||||
}}
|
`brightness(${roundToPrecision(baseBrightness, 10)})`,
|
||||||
transition={{
|
`brightness(${roundToPrecision((baseBrightness + peakBrightness) / 2, 10)})`,
|
||||||
duration: roundToPrecision(duration, 10),
|
`brightness(${roundToPrecision(peakBrightness, 10)})`,
|
||||||
delay: 0, // No delay - instant start
|
`brightness(${roundToPrecision((baseBrightness + peakBrightness) / 2, 10)})`,
|
||||||
repeat: Infinity,
|
`brightness(${roundToPrecision(baseBrightness, 10)})`,
|
||||||
ease: "easeInOut",
|
],
|
||||||
repeatDelay: 0, // No pause between cycles
|
}}
|
||||||
}}
|
transition={{
|
||||||
/>
|
duration: roundToPrecision(duration, 10),
|
||||||
);
|
delay: 0, // No delay - instant start
|
||||||
})}
|
repeat: Infinity,
|
||||||
|
ease: "easeInOut",
|
||||||
|
repeatDelay: 0, // No pause between cycles
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
|
||||||
|
|
@ -11,22 +11,22 @@ const components = {
|
||||||
types: {
|
types: {
|
||||||
image: ({ value }: any) => {
|
image: ({ value }: any) => {
|
||||||
if (!value?.asset) return null;
|
if (!value?.asset) return null;
|
||||||
|
|
||||||
const imageUrl = urlFor(value);
|
const imageUrl = urlFor(value);
|
||||||
const asset = value.asset;
|
const asset = value.asset;
|
||||||
|
|
||||||
// Get natural dimensions if available from metadata
|
// Get natural dimensions if available from metadata
|
||||||
const dimensions = asset.metadata?.dimensions;
|
const dimensions = asset.metadata?.dimensions;
|
||||||
const width = dimensions?.width || 1000;
|
const width = dimensions?.width || 1000;
|
||||||
const height = dimensions?.height || 562;
|
const height = dimensions?.height || 562;
|
||||||
const aspectRatio = dimensions ? height / width : 0.5625; // Default to 16:9 if no dimensions
|
const aspectRatio = dimensions ? height / width : 0.5625; // Default to 16:9 if no dimensions
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="my-6 lg:my-8">
|
<div className="my-6 lg:my-8">
|
||||||
<div className="max-w-3xl mx-auto">
|
<div className="max-w-3xl mx-auto">
|
||||||
<div className="relative w-full overflow-hidden rounded-lg bg-black/5">
|
<div className="relative w-full overflow-hidden rounded-lg bg-black/5">
|
||||||
<div
|
<div
|
||||||
className="relative w-full"
|
className="relative w-full"
|
||||||
style={{ paddingBottom: `${aspectRatio * 100}%` }}
|
style={{ paddingBottom: `${aspectRatio * 100}%` }}
|
||||||
>
|
>
|
||||||
<Image
|
<Image
|
||||||
|
|
@ -39,7 +39,9 @@ const components = {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{value.alt && (
|
{value.alt && (
|
||||||
<p className="mt-2 text-sm text-black/60 text-center">{value.alt}</p>
|
<p className="mt-2 text-sm text-black/60 text-center">
|
||||||
|
{value.alt}
|
||||||
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -91,12 +93,8 @@ const components = {
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
listItem: {
|
listItem: {
|
||||||
bullet: (props: any) => (
|
bullet: (props: any) => <li className="ml-4">{props.children}</li>,
|
||||||
<li className="ml-4">{props.children}</li>
|
number: (props: any) => <li className="ml-4">{props.children}</li>,
|
||||||
),
|
|
||||||
number: (props: any) => (
|
|
||||||
<li className="ml-4">{props.children}</li>
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
marks: {
|
marks: {
|
||||||
strong: ({ children }: { children: React.ReactNode }) => (
|
strong: ({ children }: { children: React.ReactNode }) => (
|
||||||
|
|
@ -109,7 +107,11 @@ const components = {
|
||||||
<a
|
<a
|
||||||
href={props.value?.href || "#"}
|
href={props.value?.href || "#"}
|
||||||
target={props.value?.href?.startsWith("http") ? "_blank" : undefined}
|
target={props.value?.href?.startsWith("http") ? "_blank" : undefined}
|
||||||
rel={props.value?.href?.startsWith("http") ? "noopener noreferrer" : undefined}
|
rel={
|
||||||
|
props.value?.href?.startsWith("http")
|
||||||
|
? "noopener noreferrer"
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
className="text-[var(--secondary)] hover:underline font-medium"
|
className="text-[var(--secondary)] hover:underline font-medium"
|
||||||
>
|
>
|
||||||
{props.children}
|
{props.children}
|
||||||
|
|
@ -121,4 +123,3 @@ const components = {
|
||||||
export function PortableText({ content }: PortableTextProps) {
|
export function PortableText({ content }: PortableTextProps) {
|
||||||
return <SanityPortableText value={content} components={components} />;
|
return <SanityPortableText value={content} components={components} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -115,7 +115,9 @@ export function UseCasesSection() {
|
||||||
What's possible with Plano
|
What's possible with Plano
|
||||||
</h2>
|
</h2>
|
||||||
<Button asChild className="hidden lg:block">
|
<Button asChild className="hidden lg:block">
|
||||||
<Link href="https://docs.plano.katanemo.com/getting-started/installation">Start building</Link>
|
<Link href="https://docs.plano.katanemo.com/getting-started/installation">
|
||||||
|
Start building
|
||||||
|
</Link>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -156,7 +158,9 @@ export function UseCasesSection() {
|
||||||
{/* Start building button - Mobile only, appears last */}
|
{/* Start building button - Mobile only, appears last */}
|
||||||
<div className="lg:hidden mt-8">
|
<div className="lg:hidden mt-8">
|
||||||
<Button asChild className="w-full">
|
<Button asChild className="w-full">
|
||||||
<Link href="https://docs.plano.katanemo.com/getting-started/installation">Start building</Link>
|
<Link href="https://docs.plano.katanemo.com/getting-started/installation">
|
||||||
|
Start building
|
||||||
|
</Link>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -284,7 +288,10 @@ export function UseCasesSection() {
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col sm:flex-row gap-3 w-full sm:w-auto order-1">
|
<div className="flex flex-col sm:flex-row gap-3 w-full sm:w-auto order-1">
|
||||||
<Button asChild className="w-full sm:w-auto">
|
<Button asChild className="w-full sm:w-auto">
|
||||||
<Link href="https://docs.plano.katanemo.com/getting-started/installation" className="flex items-center gap-2">
|
<Link
|
||||||
|
href="https://docs.plano.katanemo.com/getting-started/installation"
|
||||||
|
className="flex items-center gap-2"
|
||||||
|
>
|
||||||
Start building
|
Start building
|
||||||
<ArrowRightIcon className="w-4 h-4" />
|
<ArrowRightIcon className="w-4 h-4" />
|
||||||
</Link>
|
</Link>
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ const verticalCarouselData = [
|
||||||
category: "PROGRAMMABLE ARCHITECTURE",
|
category: "PROGRAMMABLE ARCHITECTURE",
|
||||||
title: "",
|
title: "",
|
||||||
description: [
|
description: [
|
||||||
"As agent workloads move beyond prototypes, teams end up scattering critical logic across apps: compliance checks, context \"patches,\" provider-specific quirks, etc. That glue code gets duplicated across agents, is hard to audit, and slows iteration because every policy or workflow change requires touching application code and redeploying.",
|
'As agent workloads move beyond prototypes, teams end up scattering critical logic across apps: compliance checks, context "patches," provider-specific quirks, etc. That glue code gets duplicated across agents, is hard to audit, and slows iteration because every policy or workflow change requires touching application code and redeploying.',
|
||||||
"Plano keeps that logic in one place with a programmable Agent Filter Chain—hooks that can inspect, mutate, or terminate prompt traffic early, turning common steps (policy enforcement, jailbreak checks, context engineering, tool gating, routing hints) into reusable building blocks.",
|
"Plano keeps that logic in one place with a programmable Agent Filter Chain—hooks that can inspect, mutate, or terminate prompt traffic early, turning common steps (policy enforcement, jailbreak checks, context engineering, tool gating, routing hints) into reusable building blocks.",
|
||||||
],
|
],
|
||||||
diagram: "/PromptRouting.svg",
|
diagram: "/PromptRouting.svg",
|
||||||
|
|
@ -180,11 +180,23 @@ export function VerticalCarouselSection() {
|
||||||
|
|
||||||
{/* Description */}
|
{/* Description */}
|
||||||
<div className="text-white text-sm sm:text-base lg:text-lg max-w-full lg:max-w-md -mt-0.5">
|
<div className="text-white text-sm sm:text-base lg:text-lg max-w-full lg:max-w-md -mt-0.5">
|
||||||
{verticalCarouselData[activeSlide].description.map((paragraph, index) => (
|
{verticalCarouselData[activeSlide].description.map(
|
||||||
<p key={index} className={index < verticalCarouselData[activeSlide].description.length - 1 ? "mb-4" : "mb-0"}>
|
(paragraph, index) => (
|
||||||
{paragraph}
|
<p
|
||||||
</p>
|
key={index}
|
||||||
))}
|
className={
|
||||||
|
index <
|
||||||
|
verticalCarouselData[activeSlide].description
|
||||||
|
.length -
|
||||||
|
1
|
||||||
|
? "mb-4"
|
||||||
|
: "mb-0"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{paragraph}
|
||||||
|
</p>
|
||||||
|
),
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,9 @@ export function ResearchBenchmarks() {
|
||||||
|
|
||||||
{/* Title */}
|
{/* Title */}
|
||||||
<h2 className="text-4xl sm:text-4xl md:text-5xl lg:text-4xl font-medium leading-tight tracking-[-0.06em]! text-white">
|
<h2 className="text-4xl sm:text-4xl md:text-5xl lg:text-4xl font-medium leading-tight tracking-[-0.06em]! text-white">
|
||||||
<span className="font-sans">Production excellence, outperforming frontier LLMs</span>
|
<span className="font-sans">
|
||||||
|
Production excellence, outperforming frontier LLMs
|
||||||
|
</span>
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,26 +9,34 @@ export function ResearchCTA() {
|
||||||
<div className="max-w-4xl">
|
<div className="max-w-4xl">
|
||||||
{/* Main Heading */}
|
{/* Main Heading */}
|
||||||
<h1 className="text-4xl sm:text-4xl md:text-5xl lg:text-5xl font-medium leading-tight tracking-[-0.06em]! text-white -ml-1 mb-3 mt-4">
|
<h1 className="text-4xl sm:text-4xl md:text-5xl lg:text-5xl font-medium leading-tight tracking-[-0.06em]! text-white -ml-1 mb-3 mt-4">
|
||||||
<span className="font-sans">Meet Plano-Orchestrator. Our latest models.</span>
|
<span className="font-sans">
|
||||||
|
Meet Plano-Orchestrator. Our latest models.
|
||||||
|
</span>
|
||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Description with CTA Buttons */}
|
{/* Description with CTA Buttons */}
|
||||||
<div className="max-w-5xl">
|
<div className="max-w-5xl">
|
||||||
<p className="leading-relaxed sm:text-lg md:text-lg lg:text-[18px] font-sans font-normal text-white/90 mb-6">
|
<p className="leading-relaxed sm:text-lg md:text-lg lg:text-[18px] font-sans font-normal text-white/90 mb-6">
|
||||||
Plano-Orchestrator is a family of state-of-the-art routing and orchestration models
|
Plano-Orchestrator is a family of state-of-the-art routing and
|
||||||
that decides which agent(s) or LLM(s) should handle each request, and in what sequence.
|
orchestration models that decides which agent(s) or LLM(s) should
|
||||||
Built for multi-agent orchestration systems, Plano-Orchestrator excels at analyzing
|
handle each request, and in what sequence. Built for multi-agent
|
||||||
user intent and conversation context to make precise routing and orchestration decisions.
|
orchestration systems, Plano-Orchestrator excels at analyzing user
|
||||||
|
intent and conversation context to make precise routing and
|
||||||
|
orchestration decisions.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{/* CTA Buttons */}
|
{/* CTA Buttons */}
|
||||||
<div className="flex flex-col sm:flex-row items-stretch sm:items-start gap-3 sm:gap-4">
|
<div className="flex flex-col sm:flex-row items-stretch sm:items-start gap-3 sm:gap-4">
|
||||||
<Button asChild className="w-full sm:w-auto">
|
<Button asChild className="w-full sm:w-auto">
|
||||||
<Link href="https://huggingface.co/katanemo">Download Plano models</Link>
|
<Link href="https://huggingface.co/katanemo">
|
||||||
|
Download Plano models
|
||||||
|
</Link>
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="secondary" asChild className="w-full sm:w-auto">
|
<Button variant="secondary" asChild className="w-full sm:w-auto">
|
||||||
<Link href="https://docs.plano.katanemo.com">Get Started with Plano</Link>
|
<Link href="https://docs.plano.katanemo.com">
|
||||||
|
Get Started with Plano
|
||||||
|
</Link>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -52,14 +52,16 @@ export function ResearchCapabilities() {
|
||||||
|
|
||||||
{/* Title */}
|
{/* Title */}
|
||||||
<h2 className="text-4xl sm:text-4xl md:text-5xl lg:text-4xl font-medium leading-tight tracking-[-0.06em]! text-white mb-4">
|
<h2 className="text-4xl sm:text-4xl md:text-5xl lg:text-4xl font-medium leading-tight tracking-[-0.06em]! text-white mb-4">
|
||||||
<span className="font-sans">Accurately route with confidence with no compromise</span>
|
<span className="font-sans">
|
||||||
|
Accurately route with confidence with no compromise
|
||||||
|
</span>
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<p className="text-white/90 w-full sm:w-[75%] text-sm sm:text-base leading-relaxed">
|
<p className="text-white/90 w-full sm:w-[75%] text-sm sm:text-base leading-relaxed">
|
||||||
Designed for real-world deployments, it delivers strong performance across general
|
Designed for real-world deployments, it delivers strong performance
|
||||||
conversations, coding tasks, and long-context multi-turn conversations, while remaining
|
across general conversations, coding tasks, and long-context
|
||||||
efficient enough for low-latency production environments.
|
multi-turn conversations, while remaining efficient enough for
|
||||||
|
low-latency production environments.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -67,15 +69,18 @@ export function ResearchCapabilities() {
|
||||||
<div className="lg:hidden grid grid-cols-1 gap-8">
|
<div className="lg:hidden grid grid-cols-1 gap-8">
|
||||||
{capabilitiesData.map((capability) => {
|
{capabilitiesData.map((capability) => {
|
||||||
// Map each capability to its icon
|
// Map each capability to its icon
|
||||||
const iconMap: Record<number, React.ComponentType<{ className?: string }>> = {
|
const iconMap: Record<
|
||||||
|
number,
|
||||||
|
React.ComponentType<{ className?: string }>
|
||||||
|
> = {
|
||||||
1: MessagesSquare, // Multi-turn Understanding
|
1: MessagesSquare, // Multi-turn Understanding
|
||||||
2: GitFork, // Multi-Intent Detection
|
2: GitFork, // Multi-Intent Detection
|
||||||
3: Route, // Content-Dependency Routing
|
3: Route, // Content-Dependency Routing
|
||||||
4: RefreshCw, // Conversational-Flow Handling
|
4: RefreshCw, // Conversational-Flow Handling
|
||||||
};
|
};
|
||||||
|
|
||||||
const Icon = iconMap[capability.id];
|
const Icon = iconMap[capability.id];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={capability.id} className="flex flex-col">
|
<div key={capability.id} className="flex flex-col">
|
||||||
{/* Icon Card */}
|
{/* Icon Card */}
|
||||||
|
|
@ -84,9 +89,7 @@ export function ResearchCapabilities() {
|
||||||
transition={{ duration: 0.2 }}
|
transition={{ duration: 0.2 }}
|
||||||
className="bg-gradient-to-b from-[rgba(177,184,255,0.16)] to-[rgba(17,28,132,0.035)] border-2 border-[rgba(171,178,250,0.27)] rounded-md p-6 h-40 flex items-center justify-center mb-4"
|
className="bg-gradient-to-b from-[rgba(177,184,255,0.16)] to-[rgba(17,28,132,0.035)] border-2 border-[rgba(171,178,250,0.27)] rounded-md p-6 h-40 flex items-center justify-center mb-4"
|
||||||
>
|
>
|
||||||
{Icon && (
|
{Icon && <Icon className="w-24 h-24 text-[#9797ea]" />}
|
||||||
<Icon className="w-24 h-24 text-[#9797ea]" />
|
|
||||||
)}
|
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
||||||
{/* Title */}
|
{/* Title */}
|
||||||
|
|
@ -107,15 +110,18 @@ export function ResearchCapabilities() {
|
||||||
<div className="hidden lg:grid lg:grid-cols-4 gap-6 mb-6">
|
<div className="hidden lg:grid lg:grid-cols-4 gap-6 mb-6">
|
||||||
{capabilitiesData.map((capability) => {
|
{capabilitiesData.map((capability) => {
|
||||||
// Map each capability to its icon
|
// Map each capability to its icon
|
||||||
const iconMap: Record<number, React.ComponentType<{ className?: string }>> = {
|
const iconMap: Record<
|
||||||
|
number,
|
||||||
|
React.ComponentType<{ className?: string }>
|
||||||
|
> = {
|
||||||
1: MessagesSquare, // Multi-turn Understanding
|
1: MessagesSquare, // Multi-turn Understanding
|
||||||
2: GitFork, // Multi-Intent Detection
|
2: GitFork, // Multi-Intent Detection
|
||||||
3: Route, // Content-Dependency Routing
|
3: Route, // Content-Dependency Routing
|
||||||
4: RefreshCw, // Conversational-Flow Handling
|
4: RefreshCw, // Conversational-Flow Handling
|
||||||
};
|
};
|
||||||
|
|
||||||
const Icon = iconMap[capability.id];
|
const Icon = iconMap[capability.id];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<motion.div
|
<motion.div
|
||||||
key={capability.id}
|
key={capability.id}
|
||||||
|
|
@ -123,9 +129,7 @@ export function ResearchCapabilities() {
|
||||||
transition={{ duration: 0.2 }}
|
transition={{ duration: 0.2 }}
|
||||||
className="bg-gradient-to-b from-[rgba(177,184,255,0.16)] to-[rgba(17,28,132,0.035)] border-2 border-[rgba(171,178,250,0.27)] rounded-md p-6 h-52 flex items-center justify-center"
|
className="bg-gradient-to-b from-[rgba(177,184,255,0.16)] to-[rgba(17,28,132,0.035)] border-2 border-[rgba(171,178,250,0.27)] rounded-md p-6 h-52 flex items-center justify-center"
|
||||||
>
|
>
|
||||||
{Icon && (
|
{Icon && <Icon className="w-24 h-24 text-[#9797ea]" />}
|
||||||
<Icon className="w-24 h-24 text-[#9797ea]" />
|
|
||||||
)}
|
|
||||||
</motion.div>
|
</motion.div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|
|
||||||
|
|
@ -24,9 +24,7 @@ export function ResearchHero() {
|
||||||
—
|
—
|
||||||
</span>
|
</span>
|
||||||
<span className="text-xs sm:text-sm font-[600] tracking-[-0.6px]! text-black leading-tight">
|
<span className="text-xs sm:text-sm font-[600] tracking-[-0.6px]! text-black leading-tight">
|
||||||
<span className="">
|
<span className="">Plano Orchestrator models released</span>
|
||||||
Plano Orchestrator models released
|
|
||||||
</span>
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -40,16 +38,19 @@ export function ResearchHero() {
|
||||||
{/* Description */}
|
{/* Description */}
|
||||||
<div className="max-w-70 sm:max-w-2xl relative z-10">
|
<div className="max-w-70 sm:max-w-2xl relative z-10">
|
||||||
<p className="text-base sm:text-lg md:text-xl lg:text-[22px] font-sans font-normal tracking-[-1.0px] sm:tracking-[-1.22px]! text-black">
|
<p className="text-base sm:text-lg md:text-xl lg:text-[22px] font-sans font-normal tracking-[-1.0px] sm:tracking-[-1.22px]! text-black">
|
||||||
Our applied research focuses on how to deliver agents safely, efficiently,
|
Our applied research focuses on how to deliver agents safely,
|
||||||
and with improved real-world performance — critical for any AI application,
|
efficiently, and with improved real-world performance — critical for
|
||||||
but work that sits outside of any agent's core product logic.
|
any AI application, but work that sits outside of any agent's core
|
||||||
|
product logic.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-col sm:flex-row items-stretch sm:items-start gap-3 sm:gap-4 mt-6 sm:mt-8 relative z-10">
|
<div className="flex flex-col sm:flex-row items-stretch sm:items-start gap-3 sm:gap-4 mt-6 sm:mt-8 relative z-10">
|
||||||
<Button asChild className="w-full sm:w-auto">
|
<Button asChild className="w-full sm:w-auto">
|
||||||
<Link href="https://huggingface.co/katanemo">Available on Hugging Face</Link>
|
<Link href="https://huggingface.co/katanemo">
|
||||||
</Button>
|
Available on Hugging Face
|
||||||
|
</Link>
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue