feat: redesign archgw -> plano + website

This commit is contained in:
Musa 2025-11-05 16:29:09 -08:00
parent 126b029345
commit 2a50b02d03
56 changed files with 4959 additions and 264 deletions

41
www/.gitignore vendored Normal file
View file

@ -0,0 +1,41 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
# env files (can opt-in for committing if needed)
.env*
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts

36
www/README.md Normal file
View file

@ -0,0 +1,36 @@
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
## Getting Started
First, run the development server:
```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
## Learn More
To learn more about Next.js, take a look at the following resources:
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
## Deploy on Vercel
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.

37
www/biome.json Normal file
View file

@ -0,0 +1,37 @@
{
"$schema": "https://biomejs.dev/schemas/2.2.0/schema.json",
"vcs": {
"enabled": true,
"clientKind": "git",
"useIgnoreFile": true
},
"files": {
"ignoreUnknown": true,
"includes": ["**", "!node_modules", "!.next", "!dist", "!build"]
},
"formatter": {
"enabled": true,
"indentStyle": "space",
"indentWidth": 2
},
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"suspicious": {
"noUnknownAtRules": "off"
}
},
"domains": {
"next": "recommended",
"react": "recommended"
}
},
"assist": {
"actions": {
"source": {
"organizeImports": "on"
}
}
}
}

22
www/components.json Normal file
View file

@ -0,0 +1,22 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "new-york",
"rsc": true,
"tsx": true,
"tailwind": {
"config": "",
"css": "src/app/globals.css",
"baseColor": "neutral",
"cssVariables": true,
"prefix": ""
},
"iconLibrary": "lucide",
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks"
},
"registries": {}
}

View file

@ -1,264 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" type="image/x-icon" href="https://storage.googleapis.com/arch-website-assets/favicon.ico">
<title>Arch - Intelligent Prompt Gateway</title>
<style>
body {
font-family: -apple-system, "BlinkMacSystemFont", "Segoe UI", "Helvetica Neue", "Arial", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background-color: #fff;
text-align: center;
}
header {
background-color: #fff;
padding: 20px;
display: flex;
justify-content: center;
gap: 20px;
}
header a {
text-decoration: none;
color: #666;
font-size: 16px;
padding: 10px;
transition: color 0.3s ease;
}
header a:hover {
color: #0056b3;
}
.divider {
border: 0;
height: 1px;
background-color: #ccc;
margin: 0 0 20px 0;
}
.container {
max-width: 800px;
padding: 30px;
margin: 30px auto;
}
.image-placeholder {
width: 100%;
max-width: 800px;
margin: 0 auto 20px auto;
position: relative;
overflow: hidden;
}
.image-placeholder img {
width: 100%;
height: auto;
display: block;
}
div.bold-text {
font-size: 1.4rem;
margin-bottom: 10px;
margin-top: 10px;
}
.subheading {
font-size: 1rem;
color: #666;
margin-bottom: 30px;
}
.buttons {
margin-bottom: 30px;
}
.buttons a {
text-decoration: none;
padding: 10px 20px;
font-size: 14px;
color: #fff;
background-color: #007BFF;
border-radius: 5px;
margin: 0 10px;
display: inline-block;
transition: background-color 0.3s ease;
}
.buttons a:hover {
background-color: #0056b3;
}
hr {
border: 0;
height: 1px;
background-color: #ccc;
}
.why_arch {
text-align: left;
font-size: 16px;
margin-bottom: 50px;
line-height: 1.5;
}
.why_arch blockquote {
margin: 20px 0;
padding-left: 20px;
border-left: 3px solid #ddd;
font-style: italic;
}
.features_heading {
text-align: left;
font-size: 16px;
margin-bottom: 20px;
line-height: 1.5;
}
h3 {
font-size: 16px;
color: #333;
margin-bottom: 10px;
}
.features {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 20px;
text-align: left;
}
.feature-block {
background-color: #f9f9f9;
padding: 15px;
border-radius: 10px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.05);
font-size: 14px;
}
.feature-block ul {
margin-top: 10px;
padding-left: 20px;
}
.feature-block ul li {
margin-bottom: 8px;
line-height: 1.4;
}
.feature-block a {
color: #007BFF;
text-decoration: none;
}
.feature-block a:hover {
text-decoration: underline;
}
h2.get-started {
font-weight: bold;
font-size: 1.5rem;
margin-bottom: 40px;
line-height: 2rem;
}
/* Media Queries for mobile devices */
@media screen and (max-width: 768px) {
.container {
padding: 20px;
}
h2.bold-text {
font-size: 1.25rem;
line-height: 1.75rem;
}
.buttons a {
padding: 8px 16px;
font-size: 13px;
}
.features {
grid-template-columns: 1fr;
}
h2.get-started {
font-size: 1.25rem;
line-height: 1.75rem;
}
}
</style>
</head>
<script async src="https://www.googletagmanager.com/gtag/js?id=G-F1XYQ9H653"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-F1XYQ9H653');
</script>
<body>
<header>
<a href="https://github.com/katanemo/arch">GitHub</a>
<a href="https://docs.archgw.com">Docs</a>
<a href="https://discord.gg/pGZf2gcwEc">Discord</a>
<a href="https://github.com/katanemo/arch?tab=readme-ov-file#contact">Contact</a>
</header>
<div class="container">
<div class="image-placeholder">
<img src="https://storage.googleapis.com/arch-website-assets/arch-logo.png" alt="Arch Gateway Logo" title="Arch Gateway Logo">
</div>
<a href="https://www.producthunt.com/posts/arch-3?embed=true&utm_source=badge-top-post-badge&utm_medium=badge&utm_souce=badge-arch&#0045;3" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/top-post-badge.svg?post_id=565761&theme=light&period=daily" alt="Arch - Build&#0032;fast&#0044;&#0032;hyper&#0045;personalized&#0032;agents&#0032;with&#0032;intelligent&#0032;infra | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a>
<div class="bold-text">Build <strong>fast</strong>, <strong>observable</strong>, and <strong>personalized</strong> agents</div>
<div class="subheading">Arch is an <a href="https://github.com/katanemo/arch">intelligent</a> gateway designed to protect, observe and personalize AI agents with your APIs</div>
<div class="buttons">
<a href="https://github.com/katanemo/arch?tab=readme-ov-file#getstarted">Get Started</a>
<a href="https://docs.archgw.com">Documentation</a>
</div>
<hr>
<div class="why_arch">
<h3>Why Arch?</h3>
<p>Arch is built on (and by the core contributors of) <a href="https://www.envoyproxy.io">Envoy proxy</a> with the belief that:
<blockquote>
<p><em>Prompts are nuanced and opaque user requests, which require the same capabilities as traditional HTTP requests
including secure handling, intelligent routing, robust observability, and seamless integration with backend (API)
systems for personalization — all outside business logic.</em></p>
</blockquote>
</div>
<h3 class="features_heading">Key Features</h3>
<div class="features">
<div class="feature-block">
<h3>Out-of-process architecture, built on <a href="http://envoyproxy.io/" target="_blank">Envoy</a></h3>
Arch takes a dependency on Envoy and is a self-contained process designed to run alongside your application servers.
Arch extend's Envoy's HTTP connection management subsystem, filtering, and telemetry capabilities exclusively for
prompts and LLMs.
<ul>
<li>Proven success with companies like <a href="https://www.airbnb.com" target="_blank">Airbnb</a>, <a href="https://www.dropbox.com" target="_blank">Dropbox</a>, <a href="https://www.google.com" target="_blank">Google</a>, and others.</li>
<li>Works with any application language such as Python, Java, C++, Go, PHP, etc.</li>
<li>Quick deployment and transparent upgrades.</li>
</ul>
</div>
<div class="feature-block">
<h3>Engineered with (fast) LLMs</h3>
Arch is engineered with specialized (sub-billion) LLMs that are designed for fast, cost-effective, and accurate handling of prompts.
These LLMs are best-in-class for critical prompt-related tasks like:
<ul>
<li><strong>Function Calling:</strong> Function-calling helps you personalize GenAI applications with your API operations via user prompts.</li>
<li><strong>Prompt Guards:</strong> Centrally manages safety features to prevent toxic or jailbreak prompts.</li>
<li><strong>Intent-drift detection:</strong> Able to detect shifts in user intent to improve retrieval accuracy and response efficiency.</li>
</ul>
</div>
<div class="feature-block">
<h3>Traffic Management</h3>
Arch offers several capabilities for LLM calls originating from your applications, including a vendor-agnostic SDK to make LLM calls, smart retries on errors from upstream LLMs, and automatic cutover to other LLMs configured in Arch for continuous availability and disaster recovery scenarios.
<br><br>Arch extends Envoys cluster subsystem to manage upstream connections to LLMs so that you can build resilient AI applications.
</div>
<div class="feature-block">
<h3>Front/Edge Gateway</h3>
There is substantial benefit in using the same software at the edge (observability, traffic shaping algorithms, applying guardrails, etc.) as for outbound LLM inference use cases. <br><br> Arch is exceptionally well suited as an edge gateway for AI applications. This includes TLS termination, rate limiting, and prompt-based routing.
</div>
<div class="feature-block">
<h3>Best-in-Class Monitoring</h3>
Arch offers several monitoring metrics that help you understand three critical aspects of your application: latency, token usage, and error rates by an upstream LLM provider.
<br><br> Latency measures the speed at which your application is responding to users, which includes metrics like time to first token (TFT), time per output token (TOT), and the total latency as perceived by users.
</div>
<div class="feature-block">
<h3>End-to-End Tracing</h3>
Arch propagates trace context using the W3C Trace Context standard, specifically through the <b>traceparent</b> header compatible with OpenTelemetry.
<br><br> This allows each component in the system to record its part of the request flow, enabling end-to-end tracing across the entire application. Arch ensures that developers can capture this trace data consistently and in a format compatible with various observability tools.
</div>
</div>
</div>
<h2 class="get-started">Let's get started </h2>
<div class="buttons">
<a href="https://github.com/katanemo/arch?tab=readme-ov-file#getstarted">Get Started</a>
<a href="https://docs.archgw.com">Documentation</a>
</div>
</body>
</html>

7
www/next.config.ts Normal file
View file

@ -0,0 +1,7 @@
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
/* config options here */
};
export default nextConfig;

1907
www/package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

33
www/package.json Normal file
View file

@ -0,0 +1,33 @@
{
"name": "website",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "biome check",
"format": "biome format --write"
},
"dependencies": {
"@radix-ui/react-slot": "^1.2.3",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"framer-motion": "^12.23.24",
"lucide-react": "^0.548.0",
"next": "16.0.0",
"react": "19.2.0",
"react-dom": "19.2.0",
"tailwind-merge": "^3.3.1"
},
"devDependencies": {
"@biomejs/biome": "2.2.0",
"@tailwindcss/postcss": "^4",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
"tailwindcss": "^4",
"tw-animate-css": "^1.4.0",
"typescript": "^5"
}
}

7
www/postcss.config.mjs Normal file
View file

@ -0,0 +1,7 @@
const config = {
plugins: {
"@tailwindcss/postcss": {},
},
};
export default config;

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 333 KiB

71
www/public/Contextual.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 34 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 44 KiB

View file

@ -0,0 +1,53 @@
<svg width="26" height="26" viewBox="0 0 26 26" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="26" height="26" fill="#7780D9" style="fill:#7780D9;fill:color(display-p3 0.4667 0.5020 0.8510);fill-opacity:1;"/>
<rect x="2" y="2" width="22" height="22" fill="#B9BFFF" style="fill:#B9BFFF;fill:color(display-p3 0.7246 0.7499 1.0000);fill-opacity:1;"/>
<path d="M3 3H5V5H3V3Z" fill="#B0B7FF" style="fill:#B0B7FF;fill:color(display-p3 0.6897 0.7182 1.0000);fill-opacity:1;"/>
<path d="M3 6H5V8H3V6Z" fill="#B0B7FF" style="fill:#B0B7FF;fill:color(display-p3 0.6897 0.7182 1.0000);fill-opacity:1;"/>
<path d="M3 9H5V11H3V9Z" fill="#B0B7FF" style="fill:#B0B7FF;fill:color(display-p3 0.6897 0.7182 1.0000);fill-opacity:1;"/>
<path d="M3 12H5V14H3V12Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M3 15H5V17H3V15Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M3 18H5V20H3V18Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M3 21H5V23H3V21Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M12 3H14V5H12V3Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M12 6H14V8H12V6Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M12 9H14V11H12V9Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M12 12H14V14H12V12Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M12 15H14V17H12V15Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M12 18H14V20H12V18Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M12 21H14V23H12V21Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M6 3H8V5H6V3Z" fill="#B0B7FF" style="fill:#B0B7FF;fill:color(display-p3 0.6897 0.7182 1.0000);fill-opacity:1;"/>
<path d="M6 6H8V8H6V6Z" fill="#B0B7FF" style="fill:#B0B7FF;fill:color(display-p3 0.6897 0.7182 1.0000);fill-opacity:1;"/>
<path d="M6 9H8V11H6V9Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M6 12H8V14H6V12Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M6 15H8V17H6V15Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M6 18H8V20H6V18Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M6 21H8V23H6V21Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M15 3H17V5H15V3Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M15 6H17V8H15V6Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M15 9H17V11H15V9Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M15 12H17V14H15V12Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M15 15H17V17H15V15Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M15 18H17V20H15V18Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M15 21H17V23H15V21Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M9 3H11V5H9V3Z" fill="#B0B7FF" style="fill:#B0B7FF;fill:color(display-p3 0.6897 0.7182 1.0000);fill-opacity:1;"/>
<path d="M9 6H11V8H9V6Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M9 9H11V11H9V9Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M9 12H11V14H9V12Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M9 15H11V17H9V15Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M9 18H11V20H9V18Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M9 21H11V23H9V21Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M18 3H20V5H18V3Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M18 6H20V8H18V6Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M18 9H20V11H18V9Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M18 12H20V14H18V12Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M18 15H20V17H18V15Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M18 18H20V20H18V18Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M18 21H20V23H18V21Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M21 3H23V5H21V3Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M21 6H23V8H21V6Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M21 9H23V11H21V9Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M21 12H23V14H21V12Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M21 15H23V17H21V15Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M21 18H23V20H21V18Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M21 21H23V23H21V21Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
</svg>

After

Width:  |  Height:  |  Size: 6.4 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 23 KiB

54
www/public/Logomark.svg Normal file
View file

@ -0,0 +1,54 @@
<svg width="126" height="48" viewBox="0 0 126 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M33.723 43.0923V17.2768H38.0374V20.99H39.0276L38.0374 22.0156C38.0374 20.436 38.5089 19.1983 39.4519 18.3024C40.3949 17.3829 41.668 16.9232 43.2712 16.9232C45.228 16.9232 46.7958 17.5951 47.9746 18.9389C49.1534 20.2828 49.7427 22.0863 49.7427 24.3496V29.6188C49.7427 31.1276 49.4716 32.4479 48.9294 33.5795C48.4107 34.6876 47.6681 35.5481 46.7015 36.161C45.7349 36.774 44.5914 37.0805 43.2712 37.0805C41.668 37.0805 40.3949 36.6326 39.4519 35.7367C38.5089 34.8172 38.0374 33.5677 38.0374 31.9881L39.0276 33.0137H38.002L38.1435 37.6463V43.0923H33.723ZM41.7152 33.2612C42.8468 33.2612 43.7309 32.9312 44.3675 32.271C45.004 31.6109 45.3223 30.6679 45.3223 29.442V24.5618C45.3223 23.3358 45.004 22.3928 44.3675 21.7327C43.7309 21.0725 42.8468 20.7425 41.7152 20.7425C40.6071 20.7425 39.7348 21.0843 39.0983 21.768C38.4617 22.4282 38.1435 23.3594 38.1435 24.5618V29.442C38.1435 30.6443 38.4617 31.5873 39.0983 32.271C39.7348 32.9312 40.6071 33.2612 41.7152 33.2612ZM62.9549 36.7269C61.6819 36.7269 60.562 36.4675 59.5954 35.9489C58.6524 35.4302 57.9097 34.6994 57.3675 33.7563C56.8252 32.7897 56.5541 31.6817 56.5541 30.4321V14.9075H50.3301V10.9114H60.9746V30.4321C60.9746 31.1394 61.175 31.7052 61.5758 32.1296C62.0001 32.5304 62.5659 32.7308 63.2732 32.7308H69.1436V36.7269H62.9549ZM76.2025 37.0805C74.1986 37.0805 72.619 36.55 71.4638 35.4891C70.3086 34.4282 69.731 33.0019 69.731 31.2101C69.731 29.3005 70.3675 27.827 71.6406 26.7897C72.9137 25.7523 74.7172 25.2337 77.0512 25.2337H81.8961V23.5716C81.8961 22.6285 81.5896 21.8977 80.9766 21.379C80.3636 20.8368 79.5267 20.5657 78.4658 20.5657C77.4992 20.5657 76.6976 20.7779 76.0611 21.2022C75.4245 21.6266 75.0473 22.2042 74.9294 22.935H70.6151C70.8272 21.0961 71.6524 19.6344 73.0905 18.5499C74.5286 17.4655 76.3675 16.9232 78.6072 16.9232C80.9884 16.9232 82.8627 17.5244 84.2301 18.7268C85.621 19.9055 86.3165 21.5087 86.3165 23.5362V36.7269H82.0375V33.332H81.3302L82.0375 32.3771C82.0375 33.8153 81.5071 34.9587 80.4462 35.8074C79.3852 36.6561 77.9707 37.0805 76.2025 37.0805ZM77.6524 33.7563C78.9019 33.7563 79.9157 33.438 80.6937 32.8015C81.4953 32.165 81.8961 31.3398 81.8961 30.326V27.9567H77.122C76.2261 27.9567 75.507 28.216 74.9648 28.7347C74.4225 29.2533 74.1514 29.937 74.1514 30.7858C74.1514 31.7052 74.4579 32.4361 75.0709 32.9783C75.7074 33.497 76.5679 33.7563 77.6524 33.7563ZM88.8489 36.7269V17.2768H93.1633V20.99H94.3656L93.1633 22.0156C93.1633 20.4124 93.623 19.1629 94.5424 18.267C95.4855 17.3711 96.7704 16.9232 98.3971 16.9232C100.307 16.9232 101.827 17.5598 102.959 18.8328C104.114 20.1059 104.692 21.8152 104.692 23.9606V36.7269H100.271V24.4203C100.271 23.2415 99.9649 22.3339 99.3519 21.6973C98.7389 21.0608 97.8784 20.7425 96.7704 20.7425C95.6859 20.7425 94.8254 21.0725 94.1888 21.7327C93.5758 22.3928 93.2694 23.3358 93.2694 24.5618V36.7269H88.8489ZM115.11 37.0451C113.46 37.0451 112.022 36.7387 110.796 36.1257C109.594 35.4891 108.651 34.605 107.967 33.4734C107.307 32.3182 106.977 30.9626 106.977 29.4066V24.5971C106.977 23.0411 107.307 21.6973 107.967 20.5657C108.651 19.4105 109.594 18.5264 110.796 17.9134C112.022 17.2768 113.46 16.9586 115.11 16.9586C116.784 16.9586 118.222 17.2768 119.425 17.9134C120.627 18.5264 121.558 19.4105 122.218 20.5657C122.902 21.6973 123.244 23.0293 123.244 24.5618V29.4066C123.244 30.9626 122.902 32.3182 122.218 33.4734C121.558 34.605 120.627 35.4891 119.425 36.1257C118.222 36.7387 116.784 37.0451 115.11 37.0451ZM115.11 33.1905C116.289 33.1905 117.197 32.8722 117.833 32.2357C118.493 31.5756 118.823 30.6325 118.823 29.4066V24.5971C118.823 23.3476 118.493 22.4046 117.833 21.768C117.197 21.1315 116.289 20.8132 115.11 20.8132C113.955 20.8132 113.047 21.1315 112.387 21.768C111.727 22.4046 111.397 23.3476 111.397 24.5971V29.4066C111.397 30.6325 111.727 31.5756 112.387 32.2357C113.047 32.8722 113.955 33.1905 115.11 33.1905Z" fill="#7780D9" style="fill:#7780D9;fill:color(display-p3 0.4667 0.5020 0.8510);fill-opacity:1;"/>
<rect y="11" width="26" height="26" fill="#7780D9" style="fill:#7780D9;fill:color(display-p3 0.4667 0.5020 0.8510);fill-opacity:1;"/>
<rect x="2" y="13" width="22" height="22" fill="#B9BFFF" style="fill:#B9BFFF;fill:color(display-p3 0.7246 0.7499 1.0000);fill-opacity:1;"/>
<path d="M3 14H5V16H3V14Z" fill="#B0B7FF" style="fill:#B0B7FF;fill:color(display-p3 0.6897 0.7182 1.0000);fill-opacity:1;"/>
<path d="M3 17H5V19H3V17Z" fill="#B0B7FF" style="fill:#B0B7FF;fill:color(display-p3 0.6897 0.7182 1.0000);fill-opacity:1;"/>
<path d="M3 20H5V22H3V20Z" fill="#B0B7FF" style="fill:#B0B7FF;fill:color(display-p3 0.6897 0.7182 1.0000);fill-opacity:1;"/>
<path d="M3 23H5V25H3V23Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M3 26H5V28H3V26Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M3 29H5V31H3V29Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M3 32H5V34H3V32Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M12 14H14V16H12V14Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M12 17H14V19H12V17Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M12 20H14V22H12V20Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M12 23H14V25H12V23Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M12 26H14V28H12V26Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M12 29H14V31H12V29Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M12 32H14V34H12V32Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M6 14H8V16H6V14Z" fill="#B0B7FF" style="fill:#B0B7FF;fill:color(display-p3 0.6897 0.7182 1.0000);fill-opacity:1;"/>
<path d="M6 17H8V19H6V17Z" fill="#B0B7FF" style="fill:#B0B7FF;fill:color(display-p3 0.6897 0.7182 1.0000);fill-opacity:1;"/>
<path d="M6 20H8V22H6V20Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M6 23H8V25H6V23Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M6 26H8V28H6V26Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M6 29H8V31H6V29Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M6 32H8V34H6V32Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M15 14H17V16H15V14Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M15 17H17V19H15V17Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M15 20H17V22H15V20Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M15 23H17V25H15V23Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M15 26H17V28H15V26Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M15 29H17V31H15V29Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M15 32H17V34H15V32Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M9 14H11V16H9V14Z" fill="#B0B7FF" style="fill:#B0B7FF;fill:color(display-p3 0.6897 0.7182 1.0000);fill-opacity:1;"/>
<path d="M9 17H11V19H9V17Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M9 20H11V22H9V20Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M9 23H11V25H9V23Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M9 26H11V28H9V26Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M9 29H11V31H9V29Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M9 32H11V34H9V32Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M18 14H20V16H18V14Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M18 17H20V19H18V17Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M18 20H20V22H18V20Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M18 23H20V25H18V23Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M18 26H20V28H18V26Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M18 29H20V31H18V29Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M18 32H20V34H18V32Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M21 14H23V16H21V14Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M21 17H23V19H21V17Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M21 20H23V22H21V20Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M21 23H23V25H21V23Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M21 26H23V28H21V26Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M21 29H23V31H21V29Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M21 32H23V34H21V32Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
</svg>

After

Width:  |  Height:  |  Size: 10 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 26 KiB

93
www/public/Telemetry.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 134 KiB

1
www/public/file.svg Normal file
View file

@ -0,0 +1 @@
<svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M14.5 13.5V5.41a1 1 0 0 0-.3-.7L9.8.29A1 1 0 0 0 9.08 0H1.5v13.5A2.5 2.5 0 0 0 4 16h8a2.5 2.5 0 0 0 2.5-2.5m-1.5 0v-7H8v-5H3v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1M9.5 5V2.12L12.38 5zM5.13 5h-.62v1.25h2.12V5zm-.62 3h7.12v1.25H4.5zm.62 3h-.62v1.25h7.12V11z" clip-rule="evenodd" fill="#666" fill-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 391 B

Binary file not shown.

Binary file not shown.

Binary file not shown.

1
www/public/globe.svg Normal file
View file

@ -0,0 +1 @@
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g clip-path="url(#a)"><path fill-rule="evenodd" clip-rule="evenodd" d="M10.27 14.1a6.5 6.5 0 0 0 3.67-3.45q-1.24.21-2.7.34-.31 1.83-.97 3.1M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m.48-1.52a7 7 0 0 1-.96 0H7.5a4 4 0 0 1-.84-1.32q-.38-.89-.63-2.08a40 40 0 0 0 3.92 0q-.25 1.2-.63 2.08a4 4 0 0 1-.84 1.31zm2.94-4.76q1.66-.15 2.95-.43a7 7 0 0 0 0-2.58q-1.3-.27-2.95-.43a18 18 0 0 1 0 3.44m-1.27-3.54a17 17 0 0 1 0 3.64 39 39 0 0 1-4.3 0 17 17 0 0 1 0-3.64 39 39 0 0 1 4.3 0m1.1-1.17q1.45.13 2.69.34a6.5 6.5 0 0 0-3.67-3.44q.65 1.26.98 3.1M8.48 1.5l.01.02q.41.37.84 1.31.38.89.63 2.08a40 40 0 0 0-3.92 0q.25-1.2.63-2.08a4 4 0 0 1 .85-1.32 7 7 0 0 1 .96 0m-2.75.4a6.5 6.5 0 0 0-3.67 3.44 29 29 0 0 1 2.7-.34q.31-1.83.97-3.1M4.58 6.28q-1.66.16-2.95.43a7 7 0 0 0 0 2.58q1.3.27 2.95.43a18 18 0 0 1 0-3.44m.17 4.71q-1.45-.12-2.69-.34a6.5 6.5 0 0 0 3.67 3.44q-.65-1.27-.98-3.1" fill="#666"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg>

After

Width:  |  Height:  |  Size: 1 KiB

View file

@ -0,0 +1,68 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 28.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="STANDARD_UPDATE" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
y="0px" viewBox="0 0 1000 141.83" style="enable-background:new 0 0 1000 141.83;" xml:space="preserve">
<path d="M267.52,104.26c2.51,1.01,6.23,1.66,11.16,1.96v2.11h-55.64v-2.11c4.92-0.3,8.65-0.95,11.16-1.96c2.51-1,4.25-2.61,5.2-4.83
c0.95-2.21,1.43-5.48,1.43-9.8V22.37h-0.45l-38.15,87.92h-0.45l-40.87-87.61h-0.45v66.95c0,4.32,0.5,7.59,1.51,9.8
c1,2.21,2.74,3.82,5.2,4.83c2.46,1.01,6.16,1.66,11.08,1.96v2.11H135.8v-2.11c4.92-0.3,8.62-0.95,11.08-1.96
c2.46-1,4.2-2.61,5.2-4.83c1-2.21,1.51-5.48,1.51-9.8V22.22c0-4.32-0.5-7.59-1.51-9.8c-1.01-2.21-2.74-3.82-5.2-4.83
c-2.47-1-6.16-1.66-11.08-1.96V3.52h38.08l34.78,75.93l33.73-75.93h36.29v2.11c-4.93,0.3-8.65,0.96-11.16,1.96
c-2.51,1.01-4.27,2.64-5.28,4.9c-1.01,2.26-1.51,5.5-1.51,9.73v67.41c0,4.32,0.5,7.59,1.51,9.8
C263.25,101.65,265.01,103.25,267.52,104.26z M343.12,53.44c3.11,5.73,4.67,12.21,4.67,19.45c0,7.24-1.56,13.72-4.67,19.45
c-3.12,5.73-7.46,10.16-13.04,13.27c-5.58,3.12-11.94,4.68-19.08,4.68c-7.14,0-13.47-1.56-19-4.68c-5.53-3.11-9.88-7.54-13.04-13.27
c-3.17-5.73-4.75-12.21-4.75-19.45c0-7.24,1.58-13.72,4.75-19.45s7.51-10.15,13.04-13.27c5.53-3.12,11.86-4.68,19-4.68
c7.14,0,13.5,1.56,19.08,4.68C335.66,43.29,340,47.71,343.12,53.44z M328.04,72.89c0-7.14-0.68-13.27-2.04-18.4
c-1.36-5.13-3.32-9.02-5.88-11.69c-2.56-2.66-5.61-4-9.12-4c-3.52,0-6.56,1.33-9.12,4c-2.56,2.67-4.52,6.56-5.88,11.69
c-1.36,5.13-2.04,11.26-2.04,18.4c0,7.14,0.68,13.27,2.04,18.4c1.36,5.13,3.32,9.02,5.88,11.69c2.56,2.67,5.6,4,9.12,4
c3.52,0,6.56-1.33,9.12-4c2.56-2.66,4.52-6.56,5.88-11.69C327.36,86.16,328.04,80.03,328.04,72.89z M398.92,51.63
c2.61,0,4.98,0.45,7.09,1.36V36.4c-1.31-0.6-2.86-0.9-4.67-0.9c-4.63,0-8.72,2.04-12.29,6.11c-3.57,4.07-6.35,8.75-8.93,18.07h-0.34
V36.1h-0.6l-29.86,8.6v1.96c3.42,0,6.06,0.33,7.92,0.98c1.86,0.65,3.19,1.71,4,3.17c0.8,1.46,1.21,3.44,1.21,5.96v37.4
c0,3.12-0.3,5.43-0.9,6.94c-0.6,1.51-1.71,2.64-3.32,3.39c-1.61,0.75-4.17,1.33-7.69,1.73v2.11h41.92v-2.11
c-3.52-0.3-6.16-0.83-7.92-1.58c-1.76-0.75-2.99-1.91-3.69-3.47c-0.7-1.56-1.06-3.9-1.06-7.01V64.53
C382.95,57.1,389.91,51.63,398.92,51.63z M453.56,46.52 M618.97,101.02c-0.6-1.56-0.9-3.89-0.9-7.01V59.62
c0-16.15-8.94-24.13-20.66-24.13c-11.72,0-19.25,8.3-22.47,12.72h-0.3V36.1h-0.6l-29.86,8.6v1.96c3.32,0,5.93,0.33,7.84,0.98
c1.91,0.65,3.27,1.68,4.07,3.09c0.8,1.41,1.21,3.37,1.21,5.88V94c0,3.12-0.3,5.46-0.9,7.01c-0.6,1.56-1.71,2.71-3.32,3.47
c-1.61,0.75-4.17,1.33-7.69,1.73v2.11h39.21v-2.11c-2.71-0.4-4.8-0.98-6.26-1.73c-1.46-0.75-2.44-1.91-2.94-3.47
c-0.5-1.56-0.75-3.89-0.75-7.01V53.69c3.47-4.21,7.55-8.25,14.18-8.25c9.11,0,11.91,6.87,11.91,14.63V94c0,3.12-0.28,5.46-0.83,7.01
c-0.55,1.56-1.51,2.71-2.87,3.47c-1.36,0.75-3.44,1.33-6.26,1.73v2.11h38.76v-2.11c-3.32-0.4-5.76-0.98-7.31-1.73
C620.65,103.73,619.58,102.58,618.97,101.02z M1000,87.52c-3.33,7.27-12.62,22.77-31.52,22.77c-17.95,0-32.87-14.68-32.87-36.79
c0-6.94,1.51-13.32,4.52-19.15c3.02-5.83,7.11-10.43,12.29-13.8c5.18-3.37,10.88-5.05,17.12-5.05c18.11,0,27.14,12.76,27.14,26.06v3
h-44.93c0,0.27-0.01,0.53-0.01,0.8c0,16,7.12,31.37,25.03,31.37c13.62,0,19.32-7.54,21.56-10.25L1000,87.52z M952.06,59.47h28.18
c-0.19-10.93-3.45-20.47-12.36-20.51C959.52,38.93,953.46,46.73,952.06,59.47z M799.99,101.02c-0.6-1.56-0.9-3.89-0.9-7.01V59.62
c0-5.23-0.88-9.65-2.64-13.27c-1.76-3.62-4.2-6.33-7.31-8.14c-3.12-1.81-6.69-2.71-10.71-2.71c-4.63,0-8.72,1.18-12.29,3.54
c-3.57,2.36-6.96,5.76-10.18,10.18h-0.3V0h-0.6L725.2,8.6v1.96c3.32,0,5.93,0.33,7.84,0.98c1.91,0.65,3.27,1.68,4.07,3.09
c0.8,1.41,1.21,3.37,1.21,5.88V94c0,3.12-0.3,5.46-0.9,7.01c-0.6,1.56-1.71,2.71-3.32,3.47c-1.61,0.75-4.17,1.33-7.69,1.73v2.11
h39.21v-2.11c-2.71-0.4-4.8-0.98-6.26-1.73c-1.46-0.75-2.44-1.91-2.94-3.47c-0.5-1.56-0.75-3.89-0.75-7.01V53.69
c3.47-4.21,7.55-8.25,14.18-8.25c3.72,0,6.63,1.23,8.75,3.69c2.11,2.46,3.17,6.11,3.17,10.93V94c0,3.12-0.28,5.46-0.83,7.01
c-0.55,1.56-1.51,2.71-2.87,3.47c-1.36,0.75-3.44,1.33-6.26,1.73v2.11h38.76v-2.11c-3.32-0.4-5.76-0.98-7.31-1.73
C801.67,103.73,800.6,102.58,799.99,101.02z M690.46,101.82c-22.24,0.15-39.88-17.73-39.88-46.74c0-30.66,16.43-48.54,35.22-48.54
c18.79,0,26.85,16.93,30.96,33.56l3.01-0.05V9.45c-7.06-3.91-18.64-8.32-35.47-8.32c-32.46,0-56.96,23.75-56.96,55.46
c0,30.21,20.44,54.1,55.61,53.95c19.39-0.15,32.91-11.72,39.37-20.59l-2.1-2.25C715.86,92.66,707.14,101.67,690.46,101.82z
M914.35,66.41l-10.4-4.98c-6.91-3.09-10.86-7.18-10.86-12.21c0-5.7,5.22-9.6,12.52-9.6c10.63,0,16.14,5.88,18.42,18.95h3.14v-19
c-3.12-1.21-11.36-4.07-19.75-4.07c-16.59,0-26.69,10.43-26.69,22.47c0,4.63,1.23,8.67,3.69,12.14c2.46,3.47,6.16,6.46,11.08,8.97
l10.86,5.43c7.43,3.39,10.41,6.73,10.41,11.76c0,5.56-4.48,9.91-12.97,9.91c-12.41,0-18.31-11.77-19.93-21.22h-3.14v19.45
c4.73,3.06,13.63,5.88,21.87,5.88c15.9,0,26.99-9.74,26.99-23.52C929.58,76.84,924.28,70.63,914.35,66.41z M90.03,62.64v26.99
c0,4.22,0.6,7.46,1.81,9.73c1.21,2.26,3.22,3.9,6.03,4.9c2.81,1.01,7.09,1.66,12.82,1.96v2.11H52.33v-2.11
c4.92-0.3,8.62-0.95,11.08-1.96c2.46-1,4.2-2.61,5.2-4.83c1-2.21,1.51-5.48,1.51-9.8V22.68c0-13.79-6.23-16.59-15.69-16.59
c-10.38,0-16.73,2.79-16.73,16.14v74.91c0,16.93-11,33.03-32.72,33.03c-1.68,0-3.34-0.1-4.98-0.29v-1.81
c5.16-0.31,9.34-2.06,12.52-5.29c3.52-3.57,5.28-9.42,5.28-17.57V22.22c0-4.22-0.5-7.47-1.51-9.73c-1.01-2.26-2.77-3.89-5.28-4.9
c-2.51-1-6.18-1.66-11.01-1.96V3.52h103.05c23.44,0,37.95,11.72,37.95,29.41c0,20.25-19.89,29.71-37.67,29.71H90.03z M90.03,58.59
h7.19c12.23,0,22.52-7.16,22.52-25.51c0-22.43-14.81-25.51-22.15-25.51h-7.56V58.59z M538.1,102.31c2.49,0,4.68-1.09,6.07-2.03v3.58
c-2.78,2.6-7.94,6.38-15.7,6.38c-6.54,0-12.03-4.15-13.49-10.48h-0.39c-2.55,4.82-10.34,10.91-18.84,10.91
c-10.2,0-17.71-6.8-17.71-17.14c0-8.08,5.53-13.46,14.73-16.72l21.82-7.86V58.82c0-9.21-6.66-13.46-13.88-13.46
c-7.37,0-14.17,3.12-21.25,10.34l-2.12-1.98c6.23-10.06,16.15-18.28,30.46-18.28c13.6,0,24.51,8.93,24.37,23.38l-0.28,36.13
C531.87,100.04,534,102.31,538.1,102.31z M514.59,73.67l-8.78,3.56c-6.8,2.69-11.19,5.81-11.19,13.03c0,6.09,4.25,10.34,10.2,10.34
c3.12,0,7.65-2.41,9.78-5.1V73.67z M871.01,102.31c2.5,0,4.68-1.1,6.08-2.03v3.58c-2.78,2.6-7.94,6.39-15.71,6.39
c-6.54,0-12.03-4.15-13.49-10.48h-0.39c-2.55,4.82-10.34,10.91-18.84,10.91c-10.2,0-17.71-6.8-17.71-17.14
c0-8.08,5.53-13.46,14.73-16.72l21.82-7.86V58.82c0-9.21-6.66-13.46-13.88-13.46c-7.37,0-14.17,3.12-21.25,10.34l-2.13-1.98
c6.23-10.06,16.15-18.28,30.46-18.28c13.6,0,24.51,8.93,24.37,23.38l-0.28,36.13C864.78,100.04,866.9,102.31,871.01,102.31z
M847.49,73.67l-8.78,3.56c-6.8,2.69-11.19,5.81-11.19,13.03c0,6.09,4.25,10.34,10.2,10.34c3.12,0,7.65-2.41,9.78-5.1V73.67z
M460.13,40.45c6.45,5.03,9.3,12.27,9.3,18.45c0,16.23-13.87,24.64-29.66,24.64c-4.16,0-8.18-0.59-11.85-1.75
c-2.04,1.57-3.79,3.62-3.79,6.02c0,5.16,8.41,6.2,13.43,6.49l17.12,1.18c13.72,0.89,22.42,5.75,22.42,18
c0,15.49-18.32,28.33-45,28.33c-15.49,0-26.56-5.31-26.56-14.76c0-8.21,4.52-12.91,16.14-18.49c-7.6-2.21-9.36-6.74-9.36-11.17
c0-6.06,5.41-11.5,12.74-16.66c-8.78-3.7-14.95-11.03-14.95-21.85c0-16.23,13.87-24.64,29.66-24.64c7.26,0,13.04,1.65,17.49,4.24
c3.32-6.67,9.87-14.43,21.61-14.43v13.85C472.6,35.96,464.95,36.97,460.13,40.45z M417.93,120.58c0,8.56,9.74,12.39,22.43,12.39
c12.1,0,28.47-5.46,28.47-14.17c0-5.02-2.8-6.2-10.18-6.79L429,109.81c-1.74-0.13-3.31-0.33-4.72-0.6
C420.01,112.54,417.93,115.96,417.93,120.58z M451.13,58.91c0-13.87-4.57-20.51-11.36-20.51s-11.36,6.64-11.36,20.51
s4.57,20.51,11.36,20.51S451.13,72.78,451.13,58.91z"/>
</svg>

After

Width:  |  Height:  |  Size: 7.5 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 46 KiB

View file

@ -0,0 +1 @@
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 231 30' preserveAspectRatio='xMinYMid'><path d='M99.61,19.52h15.24l-8.05-13L92,30H85.27l18-28.17a4.29,4.29,0,0,1,7-.05L128.32,30h-6.73l-3.17-5.25H103l-3.36-5.23m69.93,5.23V0.28h-5.72V27.16a2.76,2.76,0,0,0,.85,2,2.89,2.89,0,0,0,2.08.87h26l3.39-5.25H169.54M75,20.38A10,10,0,0,0,75,.28H50V30h5.71V5.54H74.65a4.81,4.81,0,0,1,0,9.62H58.54L75.6,30h8.29L72.43,20.38H75M14.88,30H32.15a14.86,14.86,0,0,0,0-29.71H14.88a14.86,14.86,0,1,0,0,29.71m16.88-5.23H15.26a9.62,9.62,0,0,1,0-19.23h16.5a9.62,9.62,0,1,1,0,19.23M140.25,30h17.63l3.34-5.23H140.64a9.62,9.62,0,1,1,0-19.23h16.75l3.38-5.25H140.25a14.86,14.86,0,1,0,0,29.71m69.87-5.23a9.62,9.62,0,0,1-9.26-7h24.42l3.36-5.24H200.86a9.61,9.61,0,0,1,9.26-7h16.76l3.35-5.25h-20.5a14.86,14.86,0,0,0,0,29.71h17.63l3.35-5.23h-20.6' transform='translate(-0.02 0)' style='fill:#C74634'/></svg>

After

Width:  |  Height:  |  Size: 874 B

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1000" height="108.08" fill="none" viewBox="0 0 1000 108.08">
<path fill="#e10600" d="M255.96 0c-11.96 0-23.37 5.8-30.8 15.26l-74.1 92.82h37.55l61.12-75.26c3.03-3.7 5.24-5.53 10-5.53 6.07 0 10.26 5.26 10.26 11.48v32.68c0 5.27-2.7 9.6-7.7 9.6h-7.56v27H297V40.4c0-5.54.15-40.39-41.05-40.39zM32.69.03C14.72.03 0 14.48 0 32.45c0 11.61 2.57 24.71 20.67 31.74l114.4 43.9V86.47c0-9.26-8.86-11.79-8.86-11.79L37.14 43.25c-3.37-1.21-5.53-3.38-5.53-7.97a8.3 8.3 0 0 1 8.37-8.24h59.66c4.03 0 8.28 3.29 8.28 7.7v7.57h27.02V.03H32.69zm291.6 0v108.06h42.42V81.07h-7.57c-5 0-7.83-4.32-7.83-9.59V38.93c0-7.97 7.83-13.91 15.13-10.8 2.7 1.2 5 3.64 6.08 6.48l19.72 51.32c5.13 13.51 17.96 22.16 32.41 22.16h.81c18.64 0 33.9-14.86 33.9-33.64V.03h-27v73.75a7.4 7.4 0 0 1-6.36 7.29 7.1 7.1 0 0 1-7.42-4.6l-24.72-67.8c-1.9-5.4-6.35-8.64-11.75-8.64H324.3zm162.27 0v27.15h81.04c14.32 0 26.88 12.56 26.88 26.88 0 14.31-12.56 26.88-26.88 26.88h-81.04v27.15h81.04a54.22 54.22 0 0 0 47.41-27.97 54.52 54.52 0 0 0 6.62-26.06c0-9.46-2.43-18.24-6.62-26.07A53.79 53.79 0 0 0 567.61.03h-81.05zm146.28 0v27.01h5.67c.67 0 1.35 0 2.16.14 4.98.67 7.97 4.73 7.97 10.13v70.78h27.01V.03h-42.81zm102.65 0c-17.97 0-32.7 14.45-32.7 32.42 0 11.61 2.58 24.71 20.67 31.74l114.4 43.9V86.47c0-9.26-8.85-11.79-8.85-11.79l-89.07-31.43c-3.37-1.21-5.53-3.38-5.53-7.97a8.3 8.3 0 0 1 8.37-8.24h59.66c4.03 0 8.28 3.29 8.28 7.7v7.57h27.02V.03H735.49zm129.44 0v108.06h26.75V69.32a3.25 3.25 0 0 1 3.24-3.24h29.45a6.3 6.3 0 0 1 4.45 1.75l42.28 38.3a7.56 7.56 0 0 0 5.09 1.96H1000V81.07h-12.97c-4.05 0-7.97-1.48-11.07-4.05l-20.12-17.7a6.96 6.96 0 0 1 0-10.4l20.12-17.69a18.23 18.23 0 0 1 11.07-4.05H1000V.03h-23.81c-1.88 0-3.7.7-5.1 1.96l-42.27 38.29a6.6 6.6 0 0 1-4.45 1.76h-29.45a3.25 3.25 0 0 1-3.24-3.25V.03h-26.75zM0 81.07v27.01h26.74V81.07H0zm702.55 0v27.01h26.74V81.07h-26.74z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View file

@ -0,0 +1,165 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 12.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 51448) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="svg2008"
sodipodi:version="0.32"
inkscape:version="0.48.5 r10040"
sodipodi:docname="T-Mobile_logo.svg"
width="523"
height="123"
viewBox="44 334 523 123"
overflow="visible"
enable-background="new 44 334 523 123"
xml:space="preserve"><metadata
id="metadata27"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
id="defs25">
</defs>
<sodipodi:namedview
units="mm"
inkscape:cy="-177.77119"
borderopacity="1.0"
pagecolor="#ffffff"
inkscape:zoom="0.78723292"
inkscape:cx="503.25509"
id="base"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:current-layer="svg2008"
inkscape:window-width="1920"
inkscape:window-height="1018"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
bordercolor="#666666"
width="186.67mm"
height="27.6mm"
inkscape:document-units="px"
showgrid="false"
inkscape:window-maximized="1"
inkscape:snap-bbox="true"
inkscape:bbox-paths="true"
inkscape:bbox-nodes="true"
inkscape:snap-bbox-edge-midpoints="true"
inkscape:snap-bbox-midpoints="true"
inkscape:object-paths="true"
inkscape:snap-intersection-paths="true"
inkscape:object-nodes="true"
inkscape:snap-smooth-nodes="true"
inkscape:snap-object-midpoints="true"
inkscape:snap-center="true"
showguides="false"
inkscape:guide-bbox="true">
<sodipodi:guide
orientation="0,1"
position="62.635787,-253.72888"
id="guide3247" /><sodipodi:guide
orientation="0,1"
position="243.25454,-217.78617"
id="guide3265" /><sodipodi:guide
orientation="0,1"
position="342.87554,-242.11217"
id="guide4070" /></sodipodi:namedview>
<path
sodipodi:type="arc"
style="color:#000000;fill:#999b9e;fill-opacity:1;fill-rule:nonzero;stroke:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="path3209"
sodipodi:cx="366.91431"
sodipodi:cy="41.449261"
sodipodi:rx="2.5044003"
sodipodi:ry="2.5044003"
d="m 369.41871,41.449261 a 2.5044003,2.5044003 0 1 1 -5.0088,0 2.5044003,2.5044003 0 1 1 5.0088,0 z"
transform="matrix(2.5267527,0,0,2.592437,-506.01172,255.1969)" /><rect
style="color:#000000;fill:#999b9e;fill-opacity:1;fill-rule:nonzero;stroke:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect3211"
width="16.107"
height="16.437"
x="523.84003"
y="391.16901" /><rect
y="391.16901"
x="204.39101"
height="16.437"
width="16.107"
id="rect3213"
style="color:#000000;fill:#999b9e;fill-opacity:1;fill-rule:nonzero;stroke:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /><rect
style="color:#000000;fill:#999b9e;fill-opacity:1;fill-rule:nonzero;stroke:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect3215"
width="16.107"
height="16.437"
x="156.07899"
y="391.16901" /><rect
y="391.16901"
x="108.5"
height="16.437"
width="16.107"
id="rect3217"
style="color:#000000;fill:#999b9e;fill-opacity:1;fill-rule:nonzero;stroke:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /><rect
style="color:#000000;fill:#999b9e;fill-opacity:1;fill-rule:nonzero;stroke:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect3219"
width="16.107"
height="16.437"
x="59.225998"
y="391.16901" /><path
style="fill:#ed008c"
inkscape:connector-curvature="0"
id="path3221"
d="m 97.909,358.36 h 1.911 c 12.343,0 18.096,6.603 20.5,24.212 l 3.822,-0.169 -0.51,-27.938 H 60.824 l -0.619,27.938 3.678,0.169 c 0.637,-6.603 1.401,-10.159 3.059,-13.715 2.931,-6.604 9.048,-10.497 16.566,-10.497 h 2.676 v 60.784 c 0,6.434 -0.382,8.466 -1.91,9.99 -1.275,1.185 -3.824,1.693 -6.756,1.693 h -2.931 v 4.063 h 34.919 v -4.063 h -2.949 c -2.913,0 -5.48,-0.509 -6.736,-1.693 -1.529,-1.524 -1.911,-3.557 -1.911,-9.99 V 358.36" /><path
inkscape:connector-curvature="0"
id="path3223"
d="m 264.053,434.891 20.35,-71.006 v 55.721 c 0,6.081 -0.346,8.218 -1.726,9.697 -1.036,1.15 -3.437,1.644 -6.099,1.644 h -1.035 v 3.944 h 28.765 v -3.944 h -1.497 c -2.646,0 -5.062,-0.493 -6.097,-1.644 -1.382,-1.479 -1.727,-3.616 -1.727,-9.697 v -47.502 c 0,-6.082 0.345,-8.383 1.727,-9.862 1.15,-0.986 3.451,-1.644 6.097,-1.644 h 1.497 v -3.781 h -22.321 l -16.799,57.364 -16.437,-57.364 h -22.206 v 3.781 h 2.07 c 6.099,0 7.249,1.315 7.249,9.205 v 45.2 c 0,7.232 -0.345,10.191 -1.381,12.328 -1.15,2.137 -3.583,3.616 -6.098,3.616 h -1.841 v 3.944 h 23.701 v -3.944 h -1.495 c -2.991,0 -5.408,-1.151 -6.805,-3.452 -1.364,-2.301 -1.709,-4.438 -1.709,-12.492 v -51.117 l 20.233,71.006 h 3.584"
style="fill:#999b9e;fill-opacity:1" /><path
inkscape:connector-curvature="0"
id="path3225"
d="m 329.044,379.335 c -14.267,0 -23.586,11.177 -23.586,28.765 0,16.93 9.319,28.436 23.226,28.436 14.035,0 23.355,-11.506 23.355,-28.6 0,-16.931 -9.32,-28.601 -22.995,-28.601 m -0.46,3.78 c 4.126,0 7.692,2.63 9.648,7.068 1.841,4.109 2.646,9.698 2.646,17.752 0,16.6 -4.027,24.818 -12.195,24.818 -8.153,0 -12.082,-8.219 -12.082,-24.983 0,-7.89 0.821,-13.478 2.662,-17.587 1.826,-4.273 5.524,-7.068 9.321,-7.068"
style="fill:#999b9e;fill-opacity:1" /><path
inkscape:connector-curvature="0"
id="path3227"
d="m 371.155,355.995 -16.339,0.822 v 3.616 h 0.789 c 4.833,0 5.885,1.644 5.885,9.369 v 53.419 c 0,6.903 -0.23,8.712 -1.15,11.67 h 3.797 c 2.859,-4.767 3.566,-5.588 4.717,-5.588 0.559,0 1.117,0.164 1.94,0.986 5.653,4.602 8.069,5.588 13.247,5.588 12.409,0 21.384,-11.999 21.384,-29.093 0,-16.108 -8.301,-26.956 -20.71,-26.956 -6.443,0 -11.144,3.123 -13.56,8.711 v -32.544 m 11.933,27.942 c 7.381,0 11.177,7.89 11.177,23.34 0,16.272 -3.912,24.655 -11.391,24.655 -8.284,0 -12.641,-8.548 -12.641,-24.162 0,-7.89 1.037,-13.313 3.453,-17.423 2.169,-3.944 5.868,-6.41 9.402,-6.41"
style="fill:#999b9e;fill-opacity:1" /><path
inkscape:connector-curvature="0"
style="fill:#999b9e;fill-opacity:1"
d="m 426.711,380.157 -16.782,0.986 v 3.616 h 1.266 c 4.815,0 5.852,1.644 5.852,9.205 v 27.778 c 0,7.562 -1.036,9.37 -5.852,9.37 h -1.825 v 3.779 h 25.051 v -3.779 h -1.809 c -4.849,0 -5.9,-1.645 -5.9,-9.37 v -41.585"
id="path3229" /><path
inkscape:connector-curvature="0"
id="path3231"
d="m 455.819,355.995 -16.782,0.822 v 3.616 h 1.251 c 4.832,0 5.867,1.644 5.867,9.369 v 51.939 c 0,7.726 -1.035,9.37 -5.867,9.37 h -1.825 v 3.779 h 25.065 v -3.779 h -1.841 c -4.849,0 -5.868,-1.645 -5.868,-9.37 v -65.746"
style="fill:#999b9e;fill-opacity:1" /><path
inkscape:connector-curvature="0"
id="path3233"
d="m 509.306,407.606 c -0.56,-17.423 -8.844,-28.271 -21.368,-28.271 -12.098,0 -20.826,11.834 -20.826,28.271 0,17.587 8.613,28.929 21.96,28.929 8.629,0 14.612,-4.603 19.56,-14.794 l -3.451,-1.808 c -4.027,8.547 -8.054,11.999 -14.268,11.999 -9.089,0 -12.984,-7.231 -13.101,-24.326 h 31.494 m -31.378,-4.11 c 0.099,-12.327 4.108,-20.052 10.568,-20.052 6.443,0 10.239,7.561 10.125,20.052 h -20.693"
style="fill:#999b9e;fill-opacity:1" /><g
id="g3235"
style="fill:#999b9e;fill-opacity:1">
<g
id="g3237"
style="fill:#999b9e;fill-opacity:1">
<path
inkscape:connector-curvature="0"
d="m 545.988,377.995 c 0.972,0 1.921,0.249 2.847,0.748 0.926,0.499 1.647,1.213 2.163,2.141 0.518,0.928 0.776,1.896 0.776,2.904 0,0.998 -0.255,1.957 -0.765,2.877 -0.508,0.921 -1.223,1.636 -2.14,2.145 -0.919,0.509 -1.879,0.764 -2.882,0.764 -1.003,0 -1.963,-0.254 -2.882,-0.764 -0.918,-0.509 -1.634,-1.223 -2.144,-2.145 -0.512,-0.92 -0.768,-1.879 -0.768,-2.877 0,-1.008 0.259,-1.976 0.779,-2.904 0.519,-0.928 1.242,-1.643 2.166,-2.141 0.93,-0.499 1.879,-0.748 2.85,-0.748 z m 0,0.964 c -0.812,0 -1.604,0.208 -2.372,0.625 -0.769,0.417 -1.371,1.011 -1.806,1.785 -0.434,0.774 -0.65,1.581 -0.65,2.418 0,0.833 0.213,1.631 0.64,2.395 0.426,0.764 1.023,1.359 1.789,1.786 0.767,0.427 1.567,0.64 2.399,0.64 0.834,0 1.632,-0.213 2.399,-0.64 0.766,-0.426 1.361,-1.021 1.785,-1.786 0.424,-0.764 0.637,-1.562 0.637,-2.395 0,-0.837 -0.216,-1.644 -0.648,-2.418 -0.432,-0.773 -1.033,-1.368 -1.805,-1.785 -0.771,-0.417 -1.56,-0.625 -2.368,-0.625 z m -2.54,8.023 v -6.23 h 2.145 c 0.731,0 1.263,0.058 1.59,0.173 0.329,0.115 0.59,0.316 0.784,0.603 0.195,0.286 0.293,0.591 0.293,0.913 0,0.455 -0.164,0.852 -0.49,1.189 -0.324,0.337 -0.757,0.527 -1.296,0.568 0.221,0.092 0.397,0.202 0.53,0.33 0.252,0.245 0.559,0.657 0.922,1.235 l 0.761,1.22 h -1.233 L 546.899,386 c -0.435,-0.769 -0.784,-1.251 -1.047,-1.447 -0.184,-0.145 -0.453,-0.217 -0.806,-0.217 h -0.592 v 2.647 h -1.006 z m 1.007,-3.502 h 1.226 c 0.584,0 0.983,-0.087 1.197,-0.262 0.214,-0.175 0.319,-0.406 0.319,-0.694 0,-0.185 -0.051,-0.351 -0.154,-0.497 -0.103,-0.146 -0.244,-0.256 -0.428,-0.328 -0.182,-0.072 -0.52,-0.107 -1.013,-0.107 h -1.147 v 1.888 z"
id="path3239"
style="fill:#999b9e;fill-opacity:1" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 9.4 KiB

1
www/public/next.svg Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

3
www/public/plano.svg Normal file
View file

@ -0,0 +1,3 @@
<svg width="91" height="34" viewBox="0 0 91 34" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0.723003 33.0923V7.27685H5.03737V10.99H6.02755L5.03737 12.0156C5.03737 10.436 5.50889 9.19827 6.45192 8.30239C7.39495 7.38294 8.66804 6.92321 10.2712 6.92321C12.228 6.92321 13.7958 7.59512 14.9746 8.93894C16.1534 10.2828 16.7427 12.0863 16.7427 14.3496V19.6188C16.7427 21.1276 16.4716 22.4479 15.9294 23.5795C15.4107 24.6876 14.6681 25.5481 13.7015 26.161C12.7349 26.774 11.5914 27.0805 10.2712 27.0805C8.66804 27.0805 7.39495 26.6326 6.45192 25.7367C5.50889 24.8172 5.03737 23.5677 5.03737 21.9881L6.02755 23.0137H5.00201L5.14346 27.6463V33.0923H0.723003ZM8.71519 23.2612C9.84683 23.2612 10.7309 22.9312 11.3675 22.271C12.004 21.6109 12.3223 20.6679 12.3223 19.442V14.5618C12.3223 13.3358 12.004 12.3928 11.3675 11.7327C10.7309 11.0725 9.84683 10.7425 8.71519 10.7425C7.60713 10.7425 6.73483 11.0843 6.09828 11.768C5.46174 12.4282 5.14346 13.3594 5.14346 14.5618V19.442C5.14346 20.6443 5.46174 21.5873 6.09828 22.271C6.73483 22.9312 7.60713 23.2612 8.71519 23.2612ZM29.9549 26.7269C28.6819 26.7269 27.562 26.4675 26.5954 25.9489C25.6524 25.4302 24.9097 24.6994 24.3675 23.7563C23.8252 22.7897 23.5541 21.6817 23.5541 20.4321V4.90748H17.3301V0.911385H27.9746V20.4321C27.9746 21.1394 28.175 21.7052 28.5758 22.1296C29.0001 22.5304 29.5659 22.7308 30.2732 22.7308H36.1436V26.7269H29.9549ZM43.2025 27.0805C41.1986 27.0805 39.619 26.55 38.4638 25.4891C37.3086 24.4282 36.731 23.0019 36.731 21.2101C36.731 19.3005 37.3675 17.827 38.6406 16.7897C39.9137 15.7523 41.7172 15.2337 44.0512 15.2337H48.8961V13.5716C48.8961 12.6285 48.5896 11.8977 47.9766 11.379C47.3636 10.8368 46.5267 10.5657 45.4658 10.5657C44.4992 10.5657 43.6976 10.7779 43.0611 11.2022C42.4245 11.6266 42.0473 12.2042 41.9294 12.935H37.6151C37.8272 11.0961 38.6524 9.63442 40.0905 8.54994C41.5286 7.46545 43.3675 6.92321 45.6072 6.92321C47.9884 6.92321 49.8627 7.52439 51.2301 8.72676C52.621 9.90555 53.3165 11.5087 53.3165 13.5362V26.7269H49.0375V23.332H48.3302L49.0375 22.3771C49.0375 23.8153 48.5071 24.9587 47.4462 25.8074C46.3852 26.6561 44.9707 27.0805 43.2025 27.0805ZM44.6524 23.7563C45.9019 23.7563 46.9157 23.438 47.6937 22.8015C48.4953 22.165 48.8961 21.3398 48.8961 20.326V17.9567H44.122C43.2261 17.9567 42.507 18.216 41.9648 18.7347C41.4225 19.2533 41.1514 19.937 41.1514 20.7858C41.1514 21.7052 41.4579 22.4361 42.0709 22.9783C42.7074 23.497 43.5679 23.7563 44.6524 23.7563ZM55.8489 26.7269V7.27685H60.1633V10.99H61.3656L60.1633 12.0156C60.1633 10.4124 60.623 9.16291 61.5424 8.26703C62.4855 7.37115 63.7704 6.92321 65.3971 6.92321C67.3067 6.92321 68.8274 7.55976 69.959 8.83285C71.1142 10.1059 71.6918 11.8152 71.6918 13.9606V26.7269H67.2714V14.4203C67.2714 13.2415 66.9649 12.3339 66.3519 11.6973C65.7389 11.0608 64.8784 10.7425 63.7704 10.7425C62.6859 10.7425 61.8254 11.0725 61.1888 11.7327C60.5758 12.3928 60.2694 13.3358 60.2694 14.5618V26.7269H55.8489ZM82.1103 27.0451C80.46 27.0451 79.0219 26.7387 77.7959 26.1257C76.5936 25.4891 75.6505 24.605 74.9668 23.4734C74.3067 22.3182 73.9766 20.9626 73.9766 19.4066V14.5971C73.9766 13.0411 74.3067 11.6973 74.9668 10.5657C75.6505 9.41045 76.5936 8.52636 77.7959 7.91339C79.0219 7.27685 80.46 6.95857 82.1103 6.95857C83.7842 6.95857 85.2223 7.27685 86.4247 7.91339C87.627 8.52636 88.5583 9.41045 89.2184 10.5657C89.9021 11.6973 90.2439 13.0293 90.2439 14.5618V19.4066C90.2439 20.9626 89.9021 22.3182 89.2184 23.4734C88.5583 24.605 87.627 25.4891 86.4247 26.1257C85.2223 26.7387 83.7842 27.0451 82.1103 27.0451ZM82.1103 23.1905C83.2891 23.1905 84.1967 22.8722 84.8333 22.2357C85.4934 21.5756 85.8235 20.6325 85.8235 19.4066V14.5971C85.8235 13.3476 85.4934 12.4046 84.8333 11.768C84.1967 11.1315 83.2891 10.8132 82.1103 10.8132C80.9551 10.8132 80.0474 11.1315 79.3873 11.768C78.7272 12.4046 78.3971 13.3476 78.3971 14.5971V19.4066C78.3971 20.6325 78.7272 21.5756 79.3873 22.2357C80.0474 22.8722 80.9551 23.1905 82.1103 23.1905Z" fill="#7780D9" style="fill:#7780D9;fill:color(display-p3 0.4667 0.5020 0.8510);fill-opacity:1;"/>
</svg>

After

Width:  |  Height:  |  Size: 4 KiB

1
www/public/vercel.svg Normal file
View file

@ -0,0 +1 @@
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1155 1000"><path d="m577.3 0 577.4 1000H0z" fill="#fff"/></svg>

After

Width:  |  Height:  |  Size: 128 B

1
www/public/window.svg Normal file
View file

@ -0,0 +1 @@
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 2.5h13v10a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1zM0 1h16v11.5a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5zm3.75 4.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5M7 4.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0m1.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5" fill="#666"/></svg>

After

Width:  |  Height:  |  Size: 385 B

BIN
www/src/app/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

217
www/src/app/globals.css Normal file
View file

@ -0,0 +1,217 @@
@import "tailwindcss";
@import "tw-animate-css";
@custom-variant dark (&:is(.dark *));
/* Font Face Declarations */
@font-face {
font-family: "IBM Plex Sans";
src: url("/fonts/IBMPlexSans-VariableFont_wdth,wght.ttf") format("truetype-variations");
font-weight: 100 700; /* Variable font weight range */
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "JetBrains Mono";
src: url("/fonts/JetBrainsMono-Regular.woff2") format("woff2");
font-weight: 400;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "JetBrains Mono";
src: url("/fonts/JetBrainsMono-Medium.woff2") format("woff2");
font-weight: 500;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "JetBrains Mono";
src: url("/fonts/jetbrains-mono-bold.woff2") format("woff2");
font-weight: 700;
font-style: normal;
font-display: swap;
}
:root {
/* Base colors */
--background: #ffffff;
--foreground: #171717;
/* Brand colors from Figma */
--primary: #7780d9;
--primary-dark: #4141b2;
--primary-darker: #2a3178;
--secondary: #9797ea;
/* Purple shades */
--purple-50: #edefff;
--purple-100: #b9bfff;
--purple-200: #b0b7ff;
--purple-300: #abb2fa;
--purple-400: #969ff4;
--purple-500: #acb3fe;
/* Neutral colors */
--muted: #787878;
--muted-foreground: #494949;
--border: #d1d1d1;
/* Dark section */
--dark-bg: #1a1a1a;
--dark-foreground: #ffffff;
--radius: 0.625rem;
--card: #ffffff;
--card-foreground: #171717;
--popover: #ffffff;
--popover-foreground: #171717;
--primary-foreground: #ffffff;
--secondary-foreground: #171717;
--accent: #edefff;
--accent-foreground: #171717;
--destructive: #ef4444;
--input: #d1d1d1;
--ring: #7780d9;
--chart-1: #7780d9;
--chart-2: #9797ea;
--chart-3: #abb2fa;
--chart-4: #969ff4;
--chart-5: #acb3fe;
--sidebar: #ffffff;
--sidebar-foreground: #171717;
--sidebar-primary: #7780d9;
--sidebar-primary-foreground: #ffffff;
--sidebar-accent: #edefff;
--sidebar-accent-foreground: #171717;
--sidebar-border: #d1d1d1;
--sidebar-ring: #7780d9;
}
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-primary: var(--primary);
--color-primary-dark: var(--primary-dark);
--color-primary-darker: var(--primary-darker);
--color-secondary: var(--secondary);
--color-purple-50: var(--purple-50);
--color-purple-100: var(--purple-100);
--color-purple-200: var(--purple-200);
--color-purple-300: var(--purple-300);
--color-purple-400: var(--purple-400);
--color-purple-500: var(--purple-500);
--color-muted: var(--muted);
--color-muted-foreground: var(--muted-foreground);
--color-border: var(--border);
--color-dark-bg: var(--dark-bg);
--color-dark-foreground: var(--dark-foreground);
/* Font families for Tailwind */
--font-sans: "IBM Plex Sans", system-ui, sans-serif;
--font-mono: "JetBrains Mono", monospace;
/* Font weights - variable font supports 100-700 */
--font-weight-thin: 100;
--font-weight-extralight: 200;
--font-weight-light: 300;
--font-weight-normal: 400;
--font-weight-medium: 500;
--font-weight-semibold: 600;
--font-weight-bold: 700;
--color-sidebar-ring: var(--sidebar-ring);
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
--color-sidebar-accent: var(--sidebar-accent);
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
--color-sidebar-primary: var(--sidebar-primary);
--color-sidebar-foreground: var(--sidebar-foreground);
--color-sidebar: var(--sidebar);
--color-chart-5: var(--chart-5);
--color-chart-4: var(--chart-4);
--color-chart-3: var(--chart-3);
--color-chart-2: var(--chart-2);
--color-chart-1: var(--chart-1);
--color-ring: var(--ring);
--color-input: var(--input);
--color-destructive: var(--destructive);
--color-accent-foreground: var(--accent-foreground);
--color-accent: var(--accent);
--color-secondary-foreground: var(--secondary-foreground);
--color-primary-foreground: var(--primary-foreground);
--color-popover-foreground: var(--popover-foreground);
--color-popover: var(--popover);
--color-card-foreground: var(--card-foreground);
--color-card: var(--card);
--radius-sm: calc(var(--radius) - 4px);
--radius-md: calc(var(--radius) - 2px);
--radius-lg: var(--radius);
--radius-xl: calc(var(--radius) + 4px);
}
/* Global letter-spacing for fonts */
.font-sans,
[class*="font-sans"] {
letter-spacing: -4.56px;
}
.font-mono,
[class*="font-mono"] {
letter-spacing: -0.96px;
}
body {
font-family: var(--font-sans);
}
.dark {
--background: oklch(0.145 0 0);
--foreground: oklch(0.985 0 0);
--card: oklch(0.205 0 0);
--card-foreground: oklch(0.985 0 0);
--popover: oklch(0.205 0 0);
--popover-foreground: oklch(0.985 0 0);
--primary: oklch(0.922 0 0);
--primary-foreground: oklch(0.205 0 0);
--secondary: oklch(0.269 0 0);
--secondary-foreground: oklch(0.985 0 0);
--muted: oklch(0.269 0 0);
--muted-foreground: oklch(0.708 0 0);
--accent: oklch(0.269 0 0);
--accent-foreground: oklch(0.985 0 0);
--destructive: oklch(0.704 0.191 22.216);
--border: oklch(1 0 0 / 10%);
--input: oklch(1 0 0 / 15%);
--ring: oklch(0.556 0 0);
--chart-1: oklch(0.488 0.243 264.376);
--chart-2: oklch(0.696 0.17 162.48);
--chart-3: oklch(0.769 0.188 70.08);
--chart-4: oklch(0.627 0.265 303.9);
--chart-5: oklch(0.645 0.246 16.439);
--sidebar: oklch(0.205 0 0);
--sidebar-foreground: oklch(0.985 0 0);
--sidebar-primary: oklch(0.488 0.243 264.376);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.269 0 0);
--sidebar-accent-foreground: oklch(0.985 0 0);
--sidebar-border: oklch(1 0 0 / 10%);
--sidebar-ring: oklch(0.556 0 0);
}
@layer base {
* {
@apply border-border outline-ring/50;
}
html {
background: linear-gradient(to top right, #ffffff, #dcdfff);
min-height: 100%;
}
body {
@apply text-foreground;
background: linear-gradient(to top right, #ffffff, #dcdfff);
min-height: 100vh;
overflow-x: hidden;
}
}

21
www/src/app/layout.tsx Normal file
View file

@ -0,0 +1,21 @@
import type { Metadata } from "next";
import "./globals.css";
export const metadata: Metadata = {
title: "Plano - The AI-native network for agents",
description: "Build and scale AI agents without handling the low-level plumbing.",
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
<body className="antialiased">
{children}
</body>
</html>
);
}

32
www/src/app/page.tsx Normal file
View file

@ -0,0 +1,32 @@
"use client";
import React from "react";
import { Navbar } from "@/components/Navbar";
import { Hero } from "@/components/Hero";
import { IntroSection } from "@/components/IntroSection";
import { IdeaToAgentSection } from "@/components/IdeaToAgentSection";
import { UseCasesSection } from "@/components/UseCasesSection";
import { VerticalCarouselSection } from "@/components/VerticalCarouselSection";
import { UnlockPotentialSection } from "@/components/UnlockPotentialSection";
import { Footer } from "@/components/Footer";
import { LogoCloud } from "@/components/LogoCloud";
export default function Home() {
return (
<div className="min-h-screen">
<Navbar />
<main className="pt-20">
<Hero />
<LogoCloud />
<IntroSection />
<IdeaToAgentSection />
<UseCasesSection />
<VerticalCarouselSection />
<UnlockPotentialSection variant="black" />
{/* Rest of the sections will be refactored next */}
</main>
<Footer />
</div>
);
}

View file

@ -0,0 +1,90 @@
import React from 'react';
interface AsciiDiagramProps {
title?: string;
content: string;
className?: string;
}
export const AsciiDiagram: React.FC<AsciiDiagramProps> = ({
title,
content,
className = ""
}) => {
return (
<div className={`max-w-4xl mx-auto mb-8 ${className}`}>
{title && (
<h2 className="text-2xl font-bold text-gray-900 dark:text-zinc-50 mb-4">
{title}
</h2>
)}
<div className="bg-gray-900 dark:bg-gray-950 rounded-lg p-6 shadow-xl overflow-x-auto">
<pre
className="relative font-mono text-xs leading-none text-white m-0 whitespace-pre"
style={{ fontFamily: 'var(--font-jetbrains-mono), monospace' }}
>
<code>{content}</code>
</pre>
</div>
</div>
);
};
// Programmatic diagram builder for non-coders
interface DiagramStep {
id: string;
label: string;
type?: 'input' | 'inner' | 'regular';
x: number;
y: number;
}
interface FlowConnection {
from: string;
to: string;
label?: string;
}
interface DiagramConfig {
title: string;
steps: DiagramStep[];
connections: FlowConnection[];
}
// Simple ASCII diagram generator
export const createDiagram = (config: DiagramConfig): string => {
// This is a simplified version - you can extend this to automatically generate
// the ASCII art from the config
// For now, return the manually created diagrams
return '';
};
// Helper to create boxes
export const createBox = (
label: string,
type: 'input' | 'inner' | 'regular' = 'regular',
width: number = 20
): string[] => {
const padding = Math.max(0, Math.floor((width - label.length) / 2));
const spaces = ' '.repeat(padding);
const remaining = width - label.length - padding;
let chars;
switch (type) {
case 'input':
chars = { tl: '╔', tr: '╗', bl: '╚', br: '╝', h: '═', v: '║' };
break;
case 'inner':
chars = { tl: '┏', tr: '┓', bl: '┗', br: '┛', h: '━', v: '┃' };
break;
case 'regular':
default:
chars = { tl: '┌', tr: '┐', bl: '└', br: '┘', h: '─', v: '│' };
}
return [
`${chars.tl}${chars.h.repeat(width)}${chars.tr}`,
`${chars.v}${spaces}${label}${' '.repeat(remaining)}${chars.v}`,
`${chars.bl}${chars.h.repeat(width)}${chars.br}`,
];
};

View file

@ -0,0 +1,32 @@
import React from 'react';
import { createFlowDiagram, FlowDiagramConfig } from '@/utils/asciiBuilder';
import { AsciiDiagram } from './AsciiDiagram';
interface DiagramBuilderProps {
config: FlowDiagramConfig;
title?: string;
}
/**
* Simple Diagram Builder Component
*
* Usage:
*
* <DiagramBuilder
* config={{
* title: "My Process",
* width: 60,
* steps: [
* { label: "Start", type: "regular" },
* { label: "Process", type: "inner" },
* { label: "End", type: "regular" }
* ]
* }}
* />
*/
export const DiagramBuilder: React.FC<DiagramBuilderProps> = ({ config, title }) => {
const asciiDiagram = createFlowDiagram(config);
return <AsciiDiagram content={asciiDiagram} title={title} />;
};

View file

@ -0,0 +1,98 @@
import React from "react";
import Link from "next/link";
import Image from "next/image";
const footerLinks = {
company: [
{ label: "Product", href: "/product" },
{ label: "Use Cases", href: "/use-cases" },
{ label: "Blog", href: "/blog" },
{ label: "Plano LLMs", href: "/llms" }
],
developerResources: [
{ label: "Documentation", href: "/docs" }
]
};
export function Footer() {
return (
<footer className="relative overflow-hidden py-24 px-6 lg:px-[102px] pb-48" style={{ background: 'linear-gradient(to top right, #ffffff, #dcdfff)' }}>
<div className="max-w-[81rem] mx-auto relative z-10">
{/* Main Grid Layout */}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-20">
{/* Left Column - Tagline and Copyright */}
<div className="flex flex-col">
<p className="font-sans text-2xl text-black tracking-[-1.7px]! leading-8 mb-8">
Plano is the powerful, intelligent platform that empowers teams to seamlessly build, automate, and scale agentic systems with ease.
</p>
{/* Copyright */}
<div className="mt-auto">
<p className="font-sans text-base text-black/63 tracking-[-0.8px]!">
© Katanemo Labs, Inc. 2025 / Plano by Katanemo Labs, Inc.
</p>
</div>
</div>
{/* Right Column - Navigation Links */}
<div className="grid grid-cols-1 sm:grid-cols-2 gap-8">
{/* Company Links */}
<div>
<h3 className="font-sans font-medium text-3xl text-black tracking-[-1.6px]! mb-6">
Company
</h3>
<nav className="space-y-4">
{footerLinks.company.map((link) => (
<Link
key={link.href}
href={link.href}
className="block font-sans text-xl text-black tracking-[-1px]! hover:text-[var(--primary)] transition-colors"
>
{link.label}
</Link>
))}
</nav>
</div>
{/* Developer Resources */}
<div>
<h3 className="font-sans font-medium text-3xl text-black tracking-[-1.6px]! mb-6">
Developer Resources
</h3>
<nav className="space-y-4">
{footerLinks.developerResources.map((link) => (
<Link
key={link.href}
href={link.href}
className="block font-sans text-xl text-black tracking-[-1px]! hover:text-[var(--primary)] transition-colors"
>
{link.label}
</Link>
))}
</nav>
</div>
</div>
</div>
</div>
{/* Half-Cut Plano Logo Background */}
<div className="absolute bottom-0 left-0 right-0 overflow-hidden pointer-events-none">
<div className="max-w-[81rem] mx-auto px-6 lg:px-[1px]">
<div className="relative w-full flex justify-start">
<Image
src="/LogoOutline.svg"
alt="Plano Logo"
width={1800}
height={200}
className="w-150 h-auto opacity-30 select-none"
style={{
transform: 'translateY(0%)', // Push logo down more while showing top part
transformOrigin: 'center bottom'
}}
/>
</div>
</div>
</div>
</footer>
);
}

View file

@ -0,0 +1,50 @@
import React from "react";
import { Button } from "./ui/button";
import Link from "next/link";
import { NetworkAnimation } from "./NetworkAnimation";
export function Hero() {
return (
<section className="relative pt-15 pb-6 px-6 lg:px-8">
<div className="hidden lg:block">
<NetworkAnimation />
</div>
<div className="max-w-[81rem] mx-auto relative z-10">
<div className="max-w-3xl mb-4">
{/* Version Badge */}
<div className="mb-6">
<div className="inline-flex items-center gap-2 px-4 py-1 rounded-full bg-[rgba(185,191,255,0.4)] border border-[var(--secondary)] shadow backdrop-blur">
<span className="text-sm font-medium text-black/65">v0.3.12</span>
<span className="text-sm font-medium text-black"></span>
<span className="text-sm font-[600] tracking-[-0.6px]! text-black">RAG Agent Launch!</span>
</div>
</div>
{/* Main Heading */}
<h1 className="text-5xl lg:text-7xl font-normal leading-tight tracking-tight text-black mb-4 flex flex-col -space-y-3">
<span className="font-sans">The AI-native </span>
<span className="font-sans font-medium text-[var(--secondary)]">network for agents</span>
</h1>
</div>
{/* Subheading with CTA Buttons on the right */}
<div className="max-w-7xl flex flex-col lg:flex-row lg:items-center lg:justify-between gap-6">
<p className="text-xl lg:text-2xl font-sans font-[500] tracking-[-1.92px]! text-black max-w-2xl">
Build and scale AI agents without handling the low-level plumbing.
</p>
{/* CTA Buttons */}
<div className="justify-self-end flex justify-end items-center gap-4">
<Button asChild>
<Link href="/get-started">Get started</Link>
</Button>
<Button variant="secondary" asChild>
<Link href="/docs">Documentation</Link>
</Button>
</div>
</div>
</div>
</section>
);
}

View file

@ -0,0 +1,161 @@
"use client";
import React, { useState, useEffect } from "react";
import { motion, AnimatePresence } from "framer-motion";
import { Button } from "./ui/button";
const carouselData = [
{
id: 1,
category: "LAUNCH FASTER",
title: "Focus on core objectives",
description: "Plano handles the heavy lifting for agentic apps with purpose-built LLMs that automate request clarification, query routing, and data extraction. Ship faster without juggling prompt engineering or infrastructure details.",
image: "/LaunchFaster.svg"
},
{
id: 2,
category: "SCALE EFFICIENTLY",
title: "Build without limits",
description: "From prototype to production, Plano scales with your needs. Handle thousands of concurrent requests while maintaining consistent performance and reliability across your agent network.",
image: "/ShipConfidently.svg"
},
{
id: 3,
category: "DEPLOY CONFIDENTLY",
title: "Production-ready infrastructure",
description: "Enterprise-grade security, monitoring, and governance built-in. Deploy your agents with confidence knowing they're protected by battle-tested infrastructure and compliance frameworks.",
image: "/BuildWithChoice.svg"
},
{
id: 4,
category: "INTEGRATE SEAMLESSLY",
title: "Connect everything",
description: "Unified API access across all major LLM providers. Switch between models, combine capabilities, and route requests intelligently without vendor lock-in or complex integrations.",
image: "/Telemetry.svg"
},
{
id: 5,
category: "OPTIMIZE CONTINUOUSLY",
title: "Learn and improve",
description: "Built-in analytics and feedback loops help your agents get smarter over time. Track performance, identify bottlenecks, and optimize workflows with real-time insights and automated improvements.",
image: "/Contextual.svg"
}
];
export function IdeaToAgentSection() {
const [currentSlide, setCurrentSlide] = useState(0);
const [isAutoPlaying, setIsAutoPlaying] = useState(true);
// Auto-advance slides
useEffect(() => {
if (!isAutoPlaying) return;
const interval = setInterval(() => {
setCurrentSlide((prev) => (prev + 1) % carouselData.length);
}, 10000); // 10 seconds per slide
return () => clearInterval(interval);
}, [isAutoPlaying]);
const handleSlideClick = (index: number) => {
setCurrentSlide(index);
setIsAutoPlaying(false);
// Resume auto-play after 10 seconds
setTimeout(() => setIsAutoPlaying(true), 10000);
};
return (
<section className="relative py-24 px-6 lg:px-[102px]">
<div className="max-w-[81rem] mx-auto">
{/* Main Heading */}
<h2 className="font-sans font-normal text-4xl tracking-[-2.96px]! text-black mb-10">
Idea to agent without overhead
</h2>
{/* Progress Indicators */}
<div className="flex gap-2 mb-12">
{carouselData.map((_, index) => (
<button
key={index}
onClick={() => handleSlideClick(index)}
className="relative h-2 rounded-full overflow-hidden transition-all duration-300 hover:opacity-80"
style={{ width: index === currentSlide ? '292px' : '293px' }}
>
{/* Background */}
<div className="absolute inset-0 bg-black/6 rounded-full" />
{/* Active Progress */}
{index === currentSlide && (
<motion.div
className="absolute inset-0 bg-[#7780d9] rounded-full"
initial={{ width: 0 }}
animate={{ width: "100%" }}
transition={{ duration: 10, ease: "linear" }}
key={currentSlide}
/>
)}
{/* Completed State */}
{index < currentSlide && (
<div className="absolute inset-0 bg-purple-200/90 rounded-full" />
)}
</button>
))}
</div>
{/* Carousel Content */}
<div className="relative min-h-[300px] lg:min-h-[400px]">
<AnimatePresence mode="wait">
<motion.div
key={currentSlide}
initial={{ opacity: 0, x: 50 }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: -50 }}
transition={{ duration: 0.5, ease: "easeInOut" }}
className="absolute inset-0"
>
<div className="flex flex-col lg:flex-row lg:justify-between lg:items-center lg:gap-12">
{/* Left Content */}
<div className="flex-1">
<div className="max-w-[692px] mt-6">
{/* Category */}
<p className="font-mono font-bold text-[#2a3178] text-xl tracking-[1.92px]! mb-4 leading-[1.102]">
{carouselData[currentSlide].category}
</p>
{/* Title */}
<h3 className="font-sans font-medium text-[#9797ea] text-5xl tracking-[-2.96px]! mb-7">
{carouselData[currentSlide].title}
</h3>
{/* Description */}
<div className="font-mono text-black text-lg leading-8 max-w-140">
<p className="mb-0">
{carouselData[currentSlide].description}
</p>
</div>
<Button className="mt-8">
Learn more
</Button>
</div>
</div>
{/* Right Image - Only show if current slide has an image */}
{carouselData[currentSlide].image && (
<div className="hidden lg:flex shrink-0 w-[400px] xl:w-[500px] justify-end items-center ">
<img
src={carouselData[currentSlide].image}
alt={carouselData[currentSlide].category}
className="w-full h-auto max-h-[450px] object-contain"
/>
</div>
)}
</div>
</motion.div>
</AnimatePresence>
</div>
</div>
</section>
);
}

View file

@ -0,0 +1,38 @@
import React from "react";
import { AsciiDiagram } from "@/components/AsciiDiagram";
import { diagrams } from "@/data/diagrams";
export function IntroSection() {
return (
<section className="relative bg-[#1a1a1a] text-white py-20 px-6 lg:px-[102px]">
<div className="max-w-324 mx-auto">
<div className="flex flex-col lg:flex-row gap-12 items-start">
{/* Left Content */}
<div className="flex-1">
{/* Heading */}
<h2 className="font-sans font-medium tracking-[-1.92px]! text-[#9797ea] text-4xl leading-[1.102] mb-6 max-w-[633px]">
Go beyond AI nascent demos
</h2>
{/* Body Text */}
<div className="font-mono tracking-[-0.96px]! text-white text-lg max-w-[713px]">
<p className="mb-0 leading-8">
Plano is the infrastructure layer for building, scaling, and routing AI agents. It sits between your app and your models, enforcing safety guardrails, orchestrating multi-agent workflows, and unifying access across large language models.
</p>
<br />
<p className="mb-0 leading-8">
Developers use Plano to build faster, platform teams use it to unify governance, and AI leads use it to run continuously learning systems that stay aligned, safe, and performant. From SaaS backends to distributed ecosystems, Plano turns raw agent logic into something you can deploy, monitor, and evolve in production.
</p>
</div>
</div>
{/* Right Diagram */}
<div className="lg:w-[660px] relative flex-shrink-0">
<AsciiDiagram content={diagrams.infrastructureLayer} className="max-w-none mx-0" />
</div>
</div>
</div>
</section>
);
}

View file

@ -0,0 +1,18 @@
import React from "react";
import Image from "next/image";
export function Logo() {
return (
<div className="flex items-center">
{/* LogoMarkSquare SVG */}
<Image
src="/Logomark.svg"
alt="Plano Logo"
width={90}
height={20}
className="flex-shrink-0"
/>
</div>
);
}

View file

@ -0,0 +1,50 @@
import React from "react";
import Image from "next/image";
const customerLogos = [
{
name: "HuggingFace",
src: "/logos/huggingface.svg"
},
{
name: "T-Mobile",
src: "/logos/tmobile.svg"
},
{
name: "Chase",
src: "/logos/chase.svg"
},
{
name: "SanDisk",
src: "/logos/sandisk.svg"
},
{
name: "Oracle",
src: "/logos/oracle.svg"
}
];
export function LogoCloud() {
return (
<section className="relative py-8 px-6 lg:px-8">
<div className="max-w-[81rem] mx-auto">
<div className="flex items-center justify-center gap-8 lg:gap-12 flex-wrap lg:flex-nowrap">
{customerLogos.map((logo) => (
<div
key={logo.name}
className="flex items-center justify-center mx-auto opacity-60 hover:opacity-80 transition-opacity duration-300 w-48 h-12"
>
<Image
src={logo.src}
alt={`${logo.name} logo`}
width={128}
height={40}
className="w-full h-full object-contain filter grayscale hover:grayscale-0 transition-all duration-300"
/>
</div>
))}
</div>
</div>
</section>
);
}

View file

@ -0,0 +1,68 @@
"use client";
import React from "react";
import Link from "next/link";
import { Logo } from "./Logo";
import { Button } from "./ui/button";
import { cn } from "@/lib/utils";
const navItems = [
{ href: "/docs", label: "docs" },
{ href: "/pricing", label: "pricing" },
{ href: "/blog", label: "blog" },
];
export function Navbar() {
return (
<nav className="fixed top-0 left-0 right-0 z-50 bg-gradient-to-b from-transparent to-white/5 backdrop-blur border-b border-neutral-200/5">
<div className="max-w-[85rem] mx-auto px-6 lg:px-8">
<div className="flex items-center justify-between h-20">
{/* Logo */}
<Link href="/" className="flex items-center">
<Logo />
</Link>
{/* Navigation Links and CTA - Far Right */}
<div className="hidden md:flex items-center justify-end gap-8">
{navItems.map((item) => (
<Link
key={item.href}
href={item.href}
className={cn(
"text-lg font-medium text-[var(--muted)]",
"hover:text-[var(--primary)] transition-colors",
"font-mono tracking-tighter"
)}
>
{item.label}
</Link>
))}
</div>
{/* Mobile Menu Button */}
<div className="md:hidden">
<button
className="p-2 rounded-md text-[var(--muted)] hover:text-[var(--primary)]"
aria-label="Toggle menu"
>
<svg
className="h-6 w-6"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M4 6h16M4 12h16M4 18h16"
/>
</svg>
</button>
</div>
</div>
</div>
</nav>
);
}

View file

@ -0,0 +1,199 @@
"use client";
import React, { useEffect, useState } from "react";
import { motion } from "framer-motion";
interface Node {
id: string;
x: number;
y: number;
size: number;
delay: number;
}
interface Connection {
from: string;
to: string;
}
interface Particle {
id: string;
connectionIndex: number;
progress: number;
}
// 4 separate groups positioned to the right of the heading text, aligned with the text vertically
const nodes: Node[] = [
// Group 1
{ id: "1", x: 20, y: 35, size: 18, delay: 0 },
{ id: "2", x: 70, y: 42, size: 12, delay: 0.8 },
{ id: "3", x: 76, y: 38, size: 16, delay: 1.6 },
// // Group 2
// { id: "4", x: 80, y: 30, size: 18, delay: 0.4 },
// { id: "5", x: 87, y: 36, size: 12, delay: 1.2 },
// { id: "6", x: 92, y: 33, size: 16, delay: 2.0 },
// Group 3
{ id: "7", x: 62, y: 48, size: 10, delay: 0.6 },
{ id: "8", x: 65, y: 52, size: 18, delay: 1.4 },
{ id: "9", x: 75, y: 48, size: 14, delay: 0.6 },
];
const connections: Connection[] = [
// Group 1 connections
{ from: "1", to: "2" },
{ from: "2", to: "3" },
// // Group 2 connections
// { from: "4", to: "5" },
// { from: "5", to: "6" },
// Group 3 connections
{ from: "7", to: "8" },
{ from: "8", to: "9" },
];
export function NetworkAnimation() {
const [particles, setParticles] = useState<Particle[]>([]);
// Create and animate particles along connections - much slower
useEffect(() => {
const createParticle = () => {
const connectionIndex = Math.floor(Math.random() * connections.length);
const particle: Particle = {
id: `particle-${Date.now()}-${Math.random()}`,
connectionIndex,
progress: 0,
};
setParticles((prev) => [...prev, particle]);
// Remove particle after animation completes
setTimeout(() => {
setParticles((prev) => prev.filter((p) => p.id !== particle.id));
}, 5000); // Slower duration
};
// Create particles at slower intervals
const interval = setInterval(createParticle, 2500);
return () => clearInterval(interval);
}, []);
// Animate particles - slower movement
useEffect(() => {
const interval = setInterval(() => {
setParticles((prev) =>
prev
.map((p) => ({ ...p, progress: p.progress + 0.008 })) // Much slower
.filter((p) => p.progress <= 1)
);
}, 50);
return () => clearInterval(interval);
}, []);
return (
<div className="absolute inset-0 pointer-events-none z-0 opacity-8 rotate-20 translate-x-40 -translate-y-40 scale-75 lg:scale-100 xl:scale-125 2xl:scale-150 [@media(min-width:1800px)]:scale-[1.60]">
<svg
className="absolute inset-0 w-full h-full rotate-10"
preserveAspectRatio="xMidYMid slice"
viewBox="790 -90 1020 840"
style={{ overflow: "visible" }}
>
<defs>
{/* Simple glow filter */}
<filter id="glow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur stdDeviation="3" result="coloredBlur" />
<feMerge>
<feMergeNode in="coloredBlur" />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
</defs>
{/* Render connections - simple lines with lower opacity */}
{connections.map((conn, index) => {
const fromNode = nodes.find((n) => n.id === conn.from);
const toNode = nodes.find((n) => n.id === conn.to);
if (!fromNode || !toNode) return null;
const x1 = (fromNode.x / 100) * 1920;
const y1 = (fromNode.y / 100) * 800;
const x2 = (toNode.x / 100) * 1920;
const y2 = (toNode.y / 100) * 800;
return (
<line
key={`line-${conn.from}-${conn.to}`}
x1={x1}
y1={y1}
x2={x2}
y2={y2}
stroke="#8b91e8"
strokeWidth="1.5"
opacity={1}
/>
);
})}
{/* Render data particles with lower opacity */}
{particles.map((particle) => {
const conn = connections[particle.connectionIndex];
const fromNode = nodes.find((n) => n.id === conn.from);
const toNode = nodes.find((n) => n.id === conn.to);
if (!fromNode || !toNode) return null;
const x = ((fromNode.x + (toNode.x - fromNode.x) * particle.progress) / 100) * 1920;
const y = ((fromNode.y + (toNode.y - fromNode.y) * particle.progress) / 100) * 800;
return (
<motion.circle
key={particle.id}
cx={x}
cy={y}
r={4}
fill="#b9bfff"
initial={{ opacity: 0 }}
animate={{
opacity: [0, 0.4, 0.4, 0]
}}
transition={{
duration: 5,
times: [0, 0.2, 0.8, 1],
ease: "linear"
}}
/>
);
})}
{/* Render nodes with subtle floating animation */}
{nodes.map((node) => {
const size = node.size;
const baseX = (node.x / 100) * 1920;
const baseY = (node.y / 100) * 800;
return (
<motion.circle
key={node.id}
cx={baseX}
cy={baseY}
r={size}
fill="#8b91e8"
animate={{
cx: [baseX - 2, baseX + 2, baseX - 2],
cy: [baseY - 2, baseY + 2, baseY - 2],
}}
transition={{
duration: 10 + node.delay,
delay: node.delay,
repeat: Infinity,
ease: "easeInOut",
}}
/>
);
})}
</svg>
</div>
);
}

View file

@ -0,0 +1,36 @@
import React from "react";
import { Button } from "./ui/button";
interface UnlockPotentialSectionProps {
variant?: "transparent" | "black";
className?: string;
}
export function UnlockPotentialSection({
variant = "transparent",
className = ""
}: UnlockPotentialSectionProps) {
const backgroundClass = variant === "black" ? "bg-[#1a1a1a]" : "";
const textColor = variant === "black" ? "text-white" : "text-black";
return (
<section className={`relative py-24 px-6 lg:px-[102px] ${backgroundClass} ${className}`}>
<div className="max-w-[81rem] mx-auto">
<div className="max-w-4xl">
<h2 className={`font-sans font-normal text-3xl lg:text-4xl tracking-[-2.88px]! ${textColor} leading-[1.03] mb-8`}>
Unlock the full potential of your applications with Plano.
</h2>
<div className="flex flex-col sm:flex-row gap-5">
<Button>
Deploy today
</Button>
<Button variant="secondaryDark">
Documentation
</Button>
</div>
</div>
</div>
</section>
);
}

View file

@ -0,0 +1,89 @@
import React from "react";
import { ArrowRightIcon } from "lucide-react";
import { Button } from "./ui/button";
const useCasesData = [
{
id: 1,
category: "FROM SAAS TO AGENTS",
title: "Transform software into active agents",
link: "Learn more"
},
{
id: 2,
category: "AGENTIC TASKS",
title: "Train models through live feedback",
link: "Learn more"
},
{
id: 3,
category: "AGENTIC ROUTING",
title: "Route logic across smart agents",
link: "Learn more"
},
{
id: 4,
category: "SAAS INTEGRATIONS",
title: "Design networks of intelligent agents",
link: "Learn more"
}
];
export function UseCasesSection() {
return (
<section className="relative py-24 px-6 lg:px-[102px]">
<div className="max-w-[81rem] mx-auto">
{/* Section Header */}
<div className="mb-14">
{/* USE CASES Badge */}
<div className="mb-6">
<div className="inline-flex items-center gap-2 px-4 py-1 rounded-full bg-[rgba(185,191,255,0.4)] border border-[var(--secondary)] shadow backdrop-blur">
<span className="font-mono font-bold text-[#2a3178] text-sm tracking-[1.62px]!">USE CASES</span>
</div>
</div>
{/* Main Heading and CTA Button */}
<div className="flex flex-col lg:flex-row lg:items-center lg:justify-between gap-6">
<h2 className="font-sans font-normal text-3xl lg:text-4xl tracking-[-2.88px]! text-black leading-[1.03]">
What's possible with Plano
</h2>
<Button>
Start building
</Button>
</div>
</div>
{/* 4 Box Grid */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
{useCasesData.map((useCase) => (
<div
key={useCase.id}
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-8 h-87 flex flex-col justify-between"
>
{/* Category */}
<div className="mb-6">
<p className="font-mono font-bold text-[#2a3178] text-lg tracking-[1.92px]! w-38 mb-6">
{useCase.category}
</p>
{/* Title */}
<h3 className="font-sans font-medium text-black text-2xl lg:text-3xl tracking-[-1.2px]! leading-[1.102]">
{useCase.title}
</h3>
</div>
{/* Learn More Link */}
<div className="mt-auto">
<button className="group flex items-center gap-2 font-mono font-bold text-[var(--primary)] text-lg tracking-[1.92px]! leading-[1.45] hover:text-[var(--primary-dark)] transition-colors">
LEARN MORE
<ArrowRightIcon className="w-4 h-4" />
</button>
</div>
</div>
))}
</div>
</div>
</section>
);
}

View file

@ -0,0 +1,125 @@
"use client";
import React, { useState } from "react";
import { motion, AnimatePresence } from "framer-motion";
import { Button } from "./ui/button";
const verticalCarouselData = [
{
id: 1,
category: "INTRODUCTION",
title: "Simple to revolutionary",
description: "By handling the critical yet complex tasks of prompt processing, Plano enables you to focus on what truly matters — achieving your business goals. With built-in capabilities like intelligent task routing, jailbreaking prevention, and centralized observability, Plano ensures your system runs smoothly and securely from the start, while continuously scaling with your needs."
},
{
id: 2,
category: "OPEN SOURCE",
title: "Built on proven foundations",
description: "Plano is built on open-source technologies and proven infrastructure patterns. This ensures transparency, community-driven development, and the ability to customize and extend the platform to meet your specific needs while maintaining enterprise-grade reliability."
},
{
id: 3,
category: "BUILT ON ENVOY",
title: "Enterprise-grade infrastructure",
description: "Leveraging the battle-tested Envoy Proxy, Plano inherits years of production-hardened networking capabilities. This foundation provides unmatched performance, reliability, and scalability for your AI agent infrastructure."
},
{
id: 4,
category: "PURPOSE-BUILT",
title: "Designed for AI agents",
description: "Unlike generic API gateways, Plano is purpose-built for AI agent workloads. Every feature is designed with prompt processing, model routing, and agent orchestration in mind, providing optimal performance for your AI applications."
},
{
id: 5,
category: "PROMPT ROUTING",
title: "Intelligent request handling",
description: "Advanced prompt routing capabilities ensure that each request is directed to the most appropriate model or agent. This intelligent routing optimizes for cost, performance, and accuracy based on your specific requirements and preferences."
}
];
export function VerticalCarouselSection() {
const [activeSlide, setActiveSlide] = useState(0);
const handleSlideClick = (index: number) => {
setActiveSlide(index);
};
return (
<section className="relative bg-[#1a1a1a] text-white py-24 px-6 lg:px-[102px]">
<div className="max-w-[81rem] mx-auto">
{/* Main Heading */}
<h2 className="font-sans font-normal text-3xl lg:text-4xl tracking-[-2.88px]! text-white leading-[1.03] mb-16 max-w-4xl">
Basic scenarios to powerful agentic apps in minutes
</h2>
{/* Vertical Carousel Layout */}
<div className="flex flex-col lg:flex-row">
{/* Left Sidebar Navigation */}
<div className="lg:w-72 flex-shrink-0">
<div className="relative space-y-6">
{/* Sliding Rectangle Indicator */}
<motion.div
className="absolute left-0 top-0 w-2 h-4 bg-[#6363d2] z-10 rounded-xs"
animate={{
y: activeSlide * 52 + 6 // Each item is ~28px text + 24px gap = 52px, +10px to center smaller rectangle
}}
transition={{
type: "spring",
stiffness: 300,
damping: 30,
duration: 0.6
}}
/>
{verticalCarouselData.map((item, index) => (
<div
key={item.id}
onClick={() => handleSlideClick(index)}
className="cursor-pointer relative pl-6 transition-all duration-300"
>
{/* Category Text */}
<span className={`font-mono font-bold text-lg tracking-[1.69px]! transition-colors duration-300 ${
index === activeSlide
? 'text-[#acb3fe]'
: 'text-[rgba(172,179,254,0.71)]'
}`}>
{item.category}
</span>
</div>
))}
</div>
</div>
{/* Right Content Area */}
<div className="flex-1 min-h-[400px] relative lg:-ml-8">
<AnimatePresence mode="wait">
<motion.div
key={activeSlide}
initial={{ opacity: 0, x: 50 }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: -50 }}
transition={{ duration: 0.5, ease: "easeInOut" }}
className="absolute inset-0"
>
<div className="max-w-2xl">
{/* Title */}
<h3 className="font-sans font-medium text-[var(--primary)] text-2xl lg:text-[34px] tracking-[-2.4px]! leading-[1.03] mb-4">
{verticalCarouselData[activeSlide].title}
</h3>
{/* Description */}
<div className="font-mono text-white text-xl lg:text-lg leading-10 tracking-[-1.2px]! max-w-md">
<p className="mb-0">
{verticalCarouselData[activeSlide].description}
</p>
</div>
</div>
</motion.div>
</AnimatePresence>
</div>
</div>
</div>
</section>
);
}

View file

@ -0,0 +1,65 @@
import * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/lib/utils"
const buttonVariants = cva(
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-[7px] font-mono font-medium tracking-[-0.989px] transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
{
variants: {
variant: {
default:
"bg-[#7780d9] border-[#4141b2] border-[1.562px] border-solid text-white hover:bg-[#7780d9]/90 text-base leading-[1.102]",
primary:
"bg-[#7780d9] border-[#4141b2] border-[1.562px] border-solid text-white hover:bg-[#7780d9]/90 text-base leading-[1.102]",
destructive:
"bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
outline:
"border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
secondary:
"bg-[#edefff] border-[#d1d1d1] border-[1.562px] border-solid text-[#494949] hover:bg-[#edefff]/90 text-base leading-[1.102]",
secondaryDark:
"bg-neutral-600 border-[#d1d1d1]/20 border-[1.562px] border-solid text-white hover:bg-[#1a1a1a]/90 text-base leading-[1.102]",
ghost:
"hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
link: "text-primary underline-offset-4 hover:underline",
},
size: {
default: "h-10 px-5 py-2 has-[>svg]:px-3",
sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
lg: "h-10 rounded-[7px] px-5 has-[>svg]:px-4",
icon: "size-9",
"icon-sm": "size-8",
"icon-lg": "size-10",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
}
)
function Button({
className,
variant,
size,
asChild = false,
...props
}: React.ComponentProps<"button"> &
VariantProps<typeof buttonVariants> & {
asChild?: boolean
}) {
const Comp = asChild ? Slot : "button"
return (
<Comp
data-slot="button"
className={cn(buttonVariants({ variant, size, className }))}
{...props}
/>
)
}
export { Button, buttonVariants }

View file

@ -0,0 +1,56 @@
import { createFlowDiagram, FlowStep } from '@/utils/asciiBuilder';
/**
* Easy-to-use diagram templates that automatically handle spacing
* Perfect for non-coders who just want to define their flow
*/
// Example: Simple 3-step process
export const createSimpleProcess = (steps: string[]) => {
return createFlowDiagram({
title: 'Process Flow',
width: 60,
steps: steps.map(label => ({ label, type: 'regular' as const, shadow: true }))
});
};
// Example: Create a nested container diagram
export const createNestedDiagram = (
title: string,
innerContent: FlowStep[],
width: number = 70
) => {
return createFlowDiagram({
title,
width,
steps: innerContent
});
};
// Pre-built templates
export const templates = {
simpleFlow: createSimpleProcess(['Start', 'Process', 'End']),
apiFlow: createFlowDiagram({
title: 'API Request Flow',
width: 65,
steps: [
{ label: 'Client Request', type: 'regular', shadow: true },
{ label: 'API Gateway', type: 'container', shadow: true },
{ label: 'Process', type: 'inner', shadow: true },
{ label: 'Response', type: 'regular', shadow: true }
]
}),
dataPipeline: createFlowDiagram({
title: 'Data Pipeline',
width: 70,
steps: [
{ label: 'Input Data', type: 'regular', shadow: true },
{ label: 'Transform', type: 'inner', shadow: true },
{ label: 'Validate', type: 'regular', shadow: true },
{ label: 'Store', type: 'regular', shadow: true }
]
})
};

View file

@ -0,0 +1,72 @@
/**
* Programmatic ASCII Diagram Builder
*
* For non-coders: Define your diagram structure with simple objects,
* and the system will automatically generate the ASCII art.
*/
interface DiagramStep {
id: string;
label: string;
type: 'input' | 'inner' | 'regular';
position: { x: number; y: number };
}
interface DiagramFlow {
from: string;
to: string;
arrow: 'right' | 'down' | 'left' | 'up';
label?: string;
}
interface DiagramConfig {
title: string;
steps: DiagramStep[];
flows: DiagramFlow[];
}
// Example: Define diagram using simple objects
export const myFlow: DiagramConfig = {
title: 'User Registration Flow',
steps: [
{ id: 'start', label: 'User', type: 'input', position: { x: 0, y: 0 } },
{ id: 'step1', label: 'Validate Email', type: 'inner', position: { x: 2, y: 0 } },
{ id: 'step2', label: 'Create Account', type: 'regular', position: { x: 2, y: 1 } },
{ id: 'step3', label: 'Send Welcome', type: 'regular', position: { x: 2, y: 2 } },
],
flows: [
{ from: 'start', to: 'step1', arrow: 'right' },
{ from: 'step1', to: 'step2', arrow: 'down' },
{ from: 'step2', to: 'step3', arrow: 'down' },
],
};
/**
* Convert diagram config to ASCII string
*
* Usage:
* import { buildDiagram } from './ascii-builder';
* const ascii = buildDiagram(myFlow);
*/
export const buildDiagram = (config: DiagramConfig): string => {
// This function would programmatically build the ASCII
// For now, return a placeholder
let result = '';
result += `╔═ ${config.title} ══╗\n`;
result += `║ Placeholder for programmatic generation ║\n`;
result += `╚════════════════════════════════════╝\n`;
// TODO: Implement automatic ASCII generation from config
// This would:
// 1. Layout boxes based on positions
// 2. Add arrows based on flows
// 3. Add shadows automatically
// 4. Handle different box types
return result;
};

85
www/src/data/diagrams.ts Normal file
View file

@ -0,0 +1,85 @@
export const diagrams = {
intentDetection: ` ╔═ Intent Detection ═════════════════════════════╗
agent Cognition
Action
Confirm action?
Execute Action
`,
dataFlow: ` ╔═ Data Pipeline ═════════════════════════════╗
Input Process Transform
Store (DB)
`,
microservices: ` ╔═ Microservices Architecture ════════════════════╗
Client API API Gateway
Service A Service B
Database
`,
simpleFlow: `╔════════════╗ ╔════════════╗ ╔════════════╗
Step 1 Step 2 Step 3
`,
infrastructureLayer: ` ╔═ plano ════════════════════════════════════════╗
client Safety Guardrails
Multi-Agent Workflows
Unified LLM Access
`,
};
export type DiagramKey = keyof typeof diagrams;

144
www/src/pages/examples.tsx Normal file
View file

@ -0,0 +1,144 @@
"use client";
import { DiagramBuilder } from "@/components/DiagramBuilder";
import { createSimpleProcess, templates } from "@/data/diagramTemplates";
import { createFlowDiagram } from "@/utils/asciiBuilder";
export default function ExamplesPage() {
return (
<div className="min-h-screen bg-zinc-50 dark:bg-black font-sans py-16 px-8">
<div className="max-w-5xl mx-auto">
<h1 className="text-4xl font-bold text-gray-900 dark:text-zinc-50 mb-8">
Programmatic Diagram Examples
</h1>
<div className="mb-12">
<h2 className="text-2xl font-bold text-gray-900 dark:text-zinc-50 mb-4">
Example 1: Simple Process Flow
</h2>
<p className="text-gray-600 dark:text-zinc-400 mb-4">
Create a simple 3-step process programmatically:
</p>
<pre className="bg-gray-900 text-white p-4 rounded-lg mb-4 overflow-x-auto">
{`import { createSimpleProcess } from '@/data/diagramTemplates';
const diagram = createSimpleProcess(['Start', 'Process', 'End']);`}
</pre>
<DiagramBuilder
config={{
title: "Simple Process",
steps: [
{ label: 'Start', type: 'regular', shadow: true },
{ label: 'Process', type: 'regular', shadow: true },
{ label: 'End', type: 'regular', shadow: true }
]
}}
/>
</div>
<div className="mb-12">
<h2 className="text-2xl font-bold text-gray-900 dark:text-zinc-50 mb-4">
Example 2: API Flow with Different Box Types
</h2>
<p className="text-gray-600 dark:text-zinc-400 mb-4">
Mix container, inner, and regular boxes:
</p>
<pre className="bg-gray-900 text-white p-4 rounded-lg mb-4 overflow-x-auto">
{`const diagram = createFlowDiagram({
title: 'API Request Flow',
width: 65,
steps: [
{ label: 'Client Request', type: 'regular', shadow: true },
{ label: 'API Gateway', type: 'container', shadow: true },
{ label: 'Process', type: 'inner', shadow: true },
{ label: 'Response', type: 'regular', shadow: true }
]
});`}
</pre>
<DiagramBuilder
config={{
title: 'API Request Flow',
width: 65,
steps: [
{ label: 'Client Request', type: 'regular', shadow: true },
{ label: 'API Gateway', type: 'container', shadow: true },
{ label: 'Process', type: 'inner', shadow: true },
{ label: 'Response', type: 'regular', shadow: true }
]
}}
/>
</div>
<div className="mb-12">
<h2 className="text-2xl font-bold text-gray-900 dark:text-zinc-50 mb-4">
Example 3: Data Pipeline
</h2>
<DiagramBuilder
config={{
title: 'Data Pipeline',
width: 70,
steps: [
{ label: 'Collect', type: 'regular', shadow: true },
{ label: 'Transform', type: 'inner', shadow: true },
{ label: 'Validate', type: 'regular', shadow: true },
{ label: 'Store', type: 'container', shadow: true }
]
}}
/>
</div>
<div className="mt-12 bg-white dark:bg-zinc-900 rounded-lg p-6 shadow">
<h3 className="text-xl font-bold text-gray-900 dark:text-zinc-50 mb-4">
How to Use Programmatic Diagrams
</h3>
<div className="space-y-4 text-gray-700 dark:text-zinc-300">
<div>
<h4 className="font-semibold mb-2">1. Import the Builder</h4>
<pre className="bg-gray-50 dark:bg-zinc-950 p-3 rounded mt-2 text-sm">
{`import { DiagramBuilder } from '@/components/DiagramBuilder';`}
</pre>
</div>
<div>
<h4 className="font-semibold mb-2">2. Define Your Steps</h4>
<pre className="bg-gray-50 dark:bg-zinc-950 p-3 rounded mt-2 text-sm overflow-x-auto">
{`<DiagramBuilder
config={{
title: "My Process",
width: 60,
steps: [
{ label: "Step 1", type: "regular", shadow: true },
{ label: "Step 2", type: "inner", shadow: true },
{ label: "Step 3", type: "container", shadow: true }
]
}}
/>`}
</pre>
</div>
<div>
<h4 className="font-semibold mb-2">3. Box Types</h4>
<ul className="list-disc list-inside space-y-1">
<li><code className="bg-gray-100 dark:bg-zinc-800 px-1 rounded">regular</code> - Thin box borders ()</li>
<li><code className="bg-gray-100 dark:bg-zinc-800 px-1 rounded">inner</code> - Thick borders ()</li>
<li><code className="bg-gray-100 dark:bg-zinc-800 px-1 rounded">container</code> - Extra thick borders ()</li>
</ul>
</div>
<div>
<h4 className="font-semibold mb-2">Benefits</h4>
<ul className="list-disc list-inside space-y-1">
<li> No manual spacing calculations</li>
<li> Automatic alignment</li>
<li> Easy for non-coders to use</li>
<li> Consistent formatting</li>
<li> Type-safe with TypeScript</li>
</ul>
</div>
</div>
</div>
</div>
</div>
);
}

View file

@ -0,0 +1,379 @@
/**
* ASCII Diagram Builder - Auto-spacing and formatting utilities
*
* This module provides utilities to ensure consistent spacing across ASCII diagrams
* similar to the intent detection diagram pattern.
*/
interface BoxDimensions {
label: string;
width: number;
height: number;
}
/**
* Calculates proper padding to center content within a container width
*/
export function calculateCenterPadding(contentWidth: number, containerWidth: number): number {
return Math.floor((containerWidth - contentWidth) / 2);
}
/**
* Creates a horizontal arrow between two positions
*/
export function createArrow(length: number, direction: '→' | '↓' | '↑' | '←' = '→'): string {
return direction.repeat(length);
}
/**
* Builds a box with specified dimensions, label, and box type
*/
export function buildBox(
label: string,
type: 'container' | 'inner' | 'regular' = 'regular',
shadow: boolean = true,
width?: number
): string[] {
const actualWidth = width || Math.max(label.length + 4, 12);
const paddedLabel = label.padStart(Math.floor((actualWidth - 2 + label.length) / 2), ' ')
.padEnd(actualWidth - 2, ' ');
const symbols = {
container: { tl: '╔', tr: '╗', bl: '╚', br: '╝', h: '═', v: '║' },
inner: { tl: '┏', tr: '┓', bl: '┗', br: '┛', h: '━', v: '┃' },
regular: { tl: '┌', tr: '┐', bl: '└', br: '┘', h: '─', v: '│' }
};
const s = symbols[type];
const shadowChar = '░';
const lines = [
s.tl + s.h.repeat(actualWidth - 2) + s.tr + (shadow ? shadowChar : ''),
s.v + paddedLabel + s.v + (shadow ? shadowChar : ''),
s.bl + s.h.repeat(actualWidth - 2) + s.br + (shadow ? shadowChar : '')
];
if (shadow) {
lines.push(' ' + shadowChar.repeat(actualWidth));
}
return lines;
}
/**
* Fixes spacing in an existing diagram by analyzing and adjusting alignment
*/
export function fixDiagramSpacing(diagram: string): string {
const lines = diagram.split('\n');
if (lines.length === 0) return diagram;
// Find the container boundaries (look for ╔ and ╚ markers)
let containerStart = -1;
let containerEnd = -1;
let containerWidth = 0;
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
if (line.includes('╔═') && line.includes('╗')) {
containerStart = i;
containerWidth = line.length;
}
if (line.includes('╚') && line.includes('╝')) {
containerEnd = i;
}
}
if (containerStart === -1 || containerEnd === -1) {
return diagram; // Can't fix if no container found
}
// The intent detection pattern shows:
// Line 2: title line with ╔═ {title} ═{fill}╗
// Lines 3-19: content with ║ on sides
// Line 20: bottom ╚══════╝
// Line 21: shadow line
// For intent detection, the container content width is about 60 chars
// Total line width including borders is about 68-70
// Content starts around position 26
// Detect pattern by looking at first content line
const firstContentLine = lines[containerStart + 1];
if (!firstContentLine) return diagram;
const leftPadding = firstContentLine.indexOf('║');
const rightPadding = containerWidth - firstContentLine.lastIndexOf('║') - 1;
// Now standardize all internal lines
const fixedLines = [...lines];
for (let i = containerStart + 1; i < containerEnd; i++) {
const line = lines[i];
const shadowIndex = line.indexOf('░');
if (line.trim().startsWith('║')) {
// This is a content line inside the container
// Standardize the padding
const content = extractContainerContent(line);
fixedLines[i] = padContainerLine(content, containerWidth, leftPadding);
}
}
return fixedLines.join('\n');
}
function extractContainerContent(line: string): string {
// Extract content between ║ characters
const startIdx = line.indexOf('║');
const endIdx = line.lastIndexOf('║');
if (startIdx === -1 || endIdx === -1 || startIdx === endIdx) return line;
return line.substring(startIdx + 1, endIdx);
}
function padContainerLine(content: string, containerWidth: number, targetLeftPad: number): string {
const padding = ' '.repeat(targetLeftPad);
const contentLength = content.length;
const rightPadding = containerWidth - targetLeftPad - contentLength - 2; // -2 for two ║
const rightPad = rightPadding > 0 ? ' '.repeat(rightPadding) : '';
return padding + '║' + content + '║' + rightPad + '░';
}
/**
* Creates a simple flow diagram programmatically
* Usage:
* ```ts
* const diagram = createFlowDiagram({
* title: "My Process",
* width: 60,
* steps: [
* { label: "Step 1", type: "regular" },
* { label: "Step 2", type: "inner" },
* { label: "Step 3", type: "regular" }
* ]
* });
* ```
*/
export interface FlowStep {
label: string;
type?: 'container' | 'inner' | 'regular';
shadow?: boolean;
}
export interface FlowDiagramConfig {
title: string;
width?: number;
steps: FlowStep[];
layout?: 'vertical' | 'horizontal';
externalElements?: FlowStep[]; // Elements outside the container (like "agent")
}
export function createFlowDiagram(config: FlowDiagramConfig): string {
const layout = config.layout || 'vertical';
if (layout === 'horizontal') {
return createHorizontalFlow(config);
} else {
return createVerticalFlow(config);
}
}
function createVerticalFlow(config: FlowDiagramConfig): string {
const width = config.width || 60;
const hasExternal = config.externalElements && config.externalElements.length > 0;
// Build external elements first
let externalBoxes: string[] = [];
let externalWidth = 0;
if (hasExternal) {
externalWidth = 20;
for (const extEl of config.externalElements!) {
const extWidth = Math.max(extEl.label.length + 4, 12);
const extBoxLines = buildBox(extEl.label, extEl.type || 'regular', extEl.shadow !== false, extWidth);
for (const extLine of extBoxLines) {
externalBoxes.push(' '.repeat(2) + extLine);
}
// Add vertical arrow if not last
if (extEl !== config.externalElements![config.externalElements!.length - 1]) {
const arrowPad = 2 + Math.floor(extWidth / 2);
externalBoxes.push(' '.repeat(arrowPad) + '▼');
}
}
}
const titleLine = hasExternal
? ` ╔═ ${config.title} ${'═'.repeat(Math.max(0, width - config.title.length - 5))}`
: `╔═ ${config.title} ${'═'.repeat(Math.max(0, width - config.title.length - 5))}`;
const lines: string[] = [];
lines.push(titleLine);
// Find max step width
const maxStepWidth = Math.max(...config.steps.map(s => s.label.length), 20);
const stepWidth = maxStepWidth + 4;
// Build internal steps
const internalLines: string[] = [];
for (let i = 0; i < config.steps.length; i++) {
const step = config.steps[i];
const boxLines = buildBox(step.label, step.type || 'regular', step.shadow !== false, stepWidth);
// Center each box
const leftPadding = calculateCenterPadding(stepWidth, width);
for (const boxLine of boxLines) {
internalLines.push(' '.repeat(leftPadding) + boxLine);
}
// Add vertical arrow between steps (except last)
if (i < config.steps.length - 1) {
const arrowPad = calculateCenterPadding(1, width);
internalLines.push(' '.repeat(arrowPad) + '│');
internalLines.push(' '.repeat(arrowPad) + '▼');
}
}
// Combine external and internal elements
const maxHeight = Math.max(externalBoxes.length, internalLines.length);
for (let row = 0; row < maxHeight; row++) {
let line = '';
// External part
if (row < externalBoxes.length) {
line += externalBoxes[row];
// Add connecting arrow on middle row
if (row === Math.floor(externalBoxes.length / 2)) {
line += '░'.repeat(6) + '─'.repeat(10) + '─▶║─';
} else {
line += '░'.repeat(6) + ' '.repeat(10) + ' ║ ';
}
} else if (hasExternal) {
line += ' '.repeat(externalWidth);
if (row < internalLines.length) {
line += '░'.repeat(6) + ' '.repeat(10) + ' ║ ';
}
} else {
line += ' '.repeat(externalWidth);
}
// Internal container part
if (row < internalLines.length) {
line += internalLines[row];
} else {
line += ' '.repeat(width);
}
line += '║░';
lines.push(line);
}
// Close container
const bottomPadding = hasExternal ? ' '.repeat(externalWidth + 16) : '';
const bottomLine = bottomPadding + '╚' + '═'.repeat(width - 1) + '╝░';
lines.push(bottomLine);
const shadowLine = (hasExternal ? ' '.repeat(externalWidth + 17) : ' ') + '░'.repeat(width);
lines.push(shadowLine);
return lines.join('\n');
}
function createHorizontalFlow(config: FlowDiagramConfig): string {
const width = config.width || 70;
const hasExternal = config.externalElements && config.externalElements.length > 0;
const lines: string[] = [];
// Calculate step widths
const maxStepWidth = Math.max(...config.steps.map(s => s.label.length), 16);
const stepWidth = maxStepWidth + 4;
const arrowGap = 12;
const totalStepWidth = config.steps.length * stepWidth + (config.steps.length - 1) * arrowGap;
const containerPadding = Math.max(4, Math.floor((width - totalStepWidth) / 2));
// Build internal boxes matrix
const boxMatrix: string[][] = [];
let maxHeight = 0;
for (const step of config.steps) {
const boxLines = buildBox(step.label, step.type || 'regular', step.shadow !== false, stepWidth);
boxMatrix.push(boxLines);
maxHeight = Math.max(maxHeight, boxLines.length);
}
// Title line - position based on external elements
const titleLeftPad = hasExternal ? 26 : 26;
const titleRepeatCount = Math.max(0, width - config.title.length - 5);
const titleLine = ' '.repeat(titleLeftPad) + `╔═ ${config.title} ${'═'.repeat(titleRepeatCount)}`;
lines.push(titleLine);
// Build external box for rendering
let externalBoxLines: string[] = [];
if (hasExternal) {
const extEl = config.externalElements![0];
const extWidth = Math.max(extEl.label.length + 4, 16);
externalBoxLines = buildBox(extEl.label, extEl.type || 'regular', extEl.shadow !== false, extWidth);
}
// Render content rows
for (let row = 0; row < maxHeight; row++) {
let line = '';
// External elements on left (if present)
if (hasExternal) {
const extRow = row < externalBoxLines.length ? row : -1;
if (extRow >= 0) {
line += ' ' + externalBoxLines[extRow];
// Add connecting arrow on middle row
if (row === Math.floor(externalBoxLines.length / 2)) {
line += '░'.repeat(5) + '─'.repeat(8) + '─▶║─';
} else {
line += '░'.repeat(5) + ' '.repeat(8) + ' ║ ';
}
} else {
line += ' '.repeat(26) + '║ ';
}
} else {
line += ' '.repeat(26) + '║ ';
}
// Internal container boxes with proper padding
line += ' '.repeat(containerPadding);
for (let i = 0; i < boxMatrix.length; i++) {
const boxLines = boxMatrix[i];
const boxLine = row < boxLines.length ? boxLines[row] : ' '.repeat(stepWidth + (config.steps[i].shadow !== false ? 1 : 0));
line += boxLine;
// Add horizontal arrow between boxes
if (i < boxMatrix.length - 1) {
if (row === Math.floor(maxHeight / 2)) {
line += '─'.repeat(arrowGap) + '►';
} else {
line += ' '.repeat(arrowGap + 1);
}
}
}
// Right padding and border
const usedWidth = containerPadding + totalStepWidth;
const rightPad = Math.max(0, width - usedWidth);
line += ' '.repeat(rightPad);
line += '║░';
lines.push(line);
}
// Close container
const bottomLine = ' '.repeat(26) + '╚' + '═'.repeat(width - 1) + '╝░';
lines.push(bottomLine);
const shadowLine = ' '.repeat(27) + '░'.repeat(width);
lines.push(shadowLine);
return lines.join('\n');
}

34
www/tsconfig.json Normal file
View file

@ -0,0 +1,34 @@
{
"compilerOptions": {
"target": "ES2017",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "react-jsx",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": ["./src/*"]
}
},
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts",
".next/dev/types/**/*.ts",
"**/*.mts"
],
"exclude": ["node_modules"]
}