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
|
|
||||||
|
|
||||||
|
|
@ -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(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -36,13 +36,13 @@ export function LogoCloud() {
|
||||||
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 (
|
||||||
|
|
|
||||||
|
|
@ -105,8 +105,8 @@ 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">
|
||||||
|
|
@ -151,47 +151,53 @@ export function NetworkAnimation({ className }: NetworkAnimationProps) {
|
||||||
{/* 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,
|
||||||
|
baseOpacity,
|
||||||
|
midOpacity,
|
||||||
|
baseBrightness,
|
||||||
|
peakBrightness,
|
||||||
|
} = getDeterministicValues(index);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<motion.path
|
<motion.path
|
||||||
key={`square-${index}`}
|
key={`square-${index}`}
|
||||||
d={`M${square.x} ${square.y}H${square.x + 2}V${square.y + 2}H${square.x}V${square.y}Z`}
|
d={`M${square.x} ${square.y}H${square.x + 2}V${square.y + 2}H${square.x}V${square.y}Z`}
|
||||||
fill={square.color}
|
fill={square.color}
|
||||||
initial={{
|
initial={{
|
||||||
opacity: roundToPrecision(baseOpacity, 10),
|
opacity: roundToPrecision(baseOpacity, 10),
|
||||||
filter: `brightness(${roundToPrecision(baseBrightness, 10)})`,
|
filter: `brightness(${roundToPrecision(baseBrightness, 10)})`,
|
||||||
}}
|
}}
|
||||||
animate={{
|
animate={{
|
||||||
opacity: [
|
opacity: [
|
||||||
roundToPrecision(baseOpacity, 10),
|
roundToPrecision(baseOpacity, 10),
|
||||||
roundToPrecision(midOpacity, 10),
|
roundToPrecision(midOpacity, 10),
|
||||||
roundToPrecision(peakOpacity, 10),
|
roundToPrecision(peakOpacity, 10),
|
||||||
roundToPrecision(midOpacity, 10),
|
roundToPrecision(midOpacity, 10),
|
||||||
roundToPrecision(baseOpacity, 10),
|
roundToPrecision(baseOpacity, 10),
|
||||||
],
|
],
|
||||||
filter: [
|
filter: [
|
||||||
`brightness(${roundToPrecision(baseBrightness, 10)})`,
|
`brightness(${roundToPrecision(baseBrightness, 10)})`,
|
||||||
`brightness(${roundToPrecision((baseBrightness + peakBrightness) / 2, 10)})`,
|
`brightness(${roundToPrecision((baseBrightness + peakBrightness) / 2, 10)})`,
|
||||||
`brightness(${roundToPrecision(peakBrightness, 10)})`,
|
`brightness(${roundToPrecision(peakBrightness, 10)})`,
|
||||||
`brightness(${roundToPrecision((baseBrightness + peakBrightness) / 2, 10)})`,
|
`brightness(${roundToPrecision((baseBrightness + peakBrightness) / 2, 10)})`,
|
||||||
`brightness(${roundToPrecision(baseBrightness, 10)})`,
|
`brightness(${roundToPrecision(baseBrightness, 10)})`,
|
||||||
],
|
],
|
||||||
}}
|
}}
|
||||||
transition={{
|
transition={{
|
||||||
duration: roundToPrecision(duration, 10),
|
duration: roundToPrecision(duration, 10),
|
||||||
delay: 0, // No delay - instant start
|
delay: 0, // No delay - instant start
|
||||||
repeat: Infinity,
|
repeat: Infinity,
|
||||||
ease: "easeInOut",
|
ease: "easeInOut",
|
||||||
repeatDelay: 0, // No pause between cycles
|
repeatDelay: 0, // No pause between cycles
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
|
||||||
|
|
@ -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,7 +69,10 @@ 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
|
||||||
|
|
@ -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,7 +110,10 @@ 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
|
||||||
|
|
@ -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