Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/web-roo-code/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"@roo-code/evals": "workspace:^",
"@roo-code/types": "workspace:^",
"@tanstack/react-query": "^5.79.0",
"@vercel/og": "^0.6.2",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"embla-carousel-auto-scroll": "^8.6.0",
Expand Down
Binary file added apps/web-roo-code/public/og/base_a.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/web-roo-code/public/og/base_b.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
165 changes: 165 additions & 0 deletions apps/web-roo-code/src/app/api/og/route.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
import { ImageResponse } from "next/og"
import { NextRequest } from "next/server"

export const runtime = "edge"

async function fetchWithTimeout(url: string, init?: RequestInit, timeoutMs = 3000) {
const controller = new AbortController()
const id = setTimeout(() => controller.abort(), timeoutMs)
try {
return await fetch(url, { ...init, signal: controller.signal })
} finally {
clearTimeout(id)
}
}

async function loadGoogleFont(font: string, text: string): Promise<ArrayBuffer | null> {
try {
const url = `https://fonts.googleapis.com/css2?family=${font}&text=${encodeURIComponent(text)}`
const cssRes = await fetchWithTimeout(url)
if (!cssRes.ok) return null
const css = await cssRes.text()

const match =
css.match(/src:\s*url\(([^)]+)\)\s*format\('(?:woff2|woff|opentype|truetype)'\)/i) ||
css.match(/url\(([^)]+)\)/i)

const fontUrl = match && match[1] ? match[1].replace(/^['"]|['"]$/g, "") : null
if (!fontUrl) return null

const res = await fetchWithTimeout(fontUrl, undefined, 5000)
if (!res.ok) return null
return await res.arrayBuffer()
} catch {
return null
}
}

export async function GET(request: NextRequest) {
const requestUrl = new URL(request.url)
const { searchParams } = requestUrl

// Get title and description from query params
const title = searchParams.get("title") || "Roo Code"
const description = searchParams.get("description") || ""

// Combine all text that will be displayed for font loading
const displayText = title + description

// Check if we should try to use the background image
const useBackgroundImage = searchParams.get("bg") !== "false"

// Dynamically get the base URL from the current request
// This ensures it works correctly in development, preview, and production environments
const baseUrl = `${requestUrl.protocol}//${requestUrl.host}`
const variant = title.length % 2 === 0 ? "a" : "b"
const backgroundUrl = `${baseUrl}/og/base_${variant}.png`

// Preload fonts with graceful fallbacks
const regularFont = await loadGoogleFont("Inter", displayText)
const boldFont = await loadGoogleFont("Inter:wght@700", displayText)
const fonts: { name: string; data: ArrayBuffer; style?: "normal" | "italic"; weight?: 400 | 700 }[] = []
if (regularFont) {
fonts.push({ name: "Inter", data: regularFont, style: "normal", weight: 400 })
}
if (boldFont) {
fonts.push({ name: "Inter", data: boldFont, style: "normal", weight: 700 })
}

return new ImageResponse(
(
<div
style={{
width: "100%",
height: "100%",
display: "flex",
position: "relative",
// Use gradient background as default/fallback
background: "linear-gradient(135deg, #1e3a5f 0%, #0f1922 50%, #1a2332 100%)",
}}>
{/* Optional Background Image - only render if explicitly requested */}
{useBackgroundImage && (
<div
style={{
position: "absolute",
top: 0,
left: 0,
width: "100%",
height: "100%",
display: "flex",
}}>
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src={backgroundUrl}
alt=""
width={1200}
height={630}
style={{
width: "100%",
height: "100%",
objectFit: "cover",
}}
/>
</div>
)}

{/* Text Content */}
<div
style={{
position: "absolute",
display: "flex",
flexDirection: "column",
justifyContent: "flex-end",
top: "220px",
left: "80px",
right: "80px",
bottom: "80px",
}}>
{/* Main Title */}
<h1
style={{
fontSize: 70,
fontWeight: 700,
fontFamily: "Inter, Helvetica Neue, Helvetica, sans-serif",
color: "white",
lineHeight: 1.2,
margin: 0,
maxHeight: "2.4em",
overflow: "hidden",
}}>
{title}
</h1>

{/* Secondary Description */}
{description && (
<h2
style={{
fontSize: 70,
fontWeight: 400,
fontFamily: "Inter, Helvetica Neue, Helvetica, Arial, sans-serif",
color: "rgba(255, 255, 255, 0.9)",
lineHeight: 1.2,
margin: 0,
maxHeight: "2.4em",
overflow: "hidden",
}}>
{description}
</h2>
)}
</div>
</div>
),
{
width: 1200,
height: 630,
fonts: fonts.length ? fonts : undefined,
// Cache for 7 days in production, 3 seconds in development
headers: {
"Cache-Control":
process.env.NODE_ENV === "production"
? "public, max-age=604800, s-maxage=604800, stale-while-revalidate=86400"
: "public, max-age=3, s-maxage=3",
},
},
)
}
13 changes: 7 additions & 6 deletions apps/web-roo-code/src/app/cloud/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,15 @@ import type { Metadata } from "next"
import { Button } from "@/components/ui"
import { AnimatedBackground } from "@/components/homepage"
import { SEO } from "@/lib/seo"
import { ogImageUrl } from "@/lib/og"
import { EXTERNAL_LINKS } from "@/lib/constants"
import Image from "next/image"

const TITLE = "Roo Code Cloud"
const DESCRIPTION =
"Roo Code Cloud gives you and your team the tools to take AI-coding to the next level with cloud agents, remote control, and more."
const OG_DESCRIPTION = "Go way beyond the IDE"
const PATH = "/cloud"
const OG_IMAGE = SEO.ogImage

export const metadata: Metadata = {
title: TITLE,
Expand All @@ -38,10 +39,10 @@ export const metadata: Metadata = {
siteName: SEO.name,
images: [
{
url: OG_IMAGE.url,
width: OG_IMAGE.width,
height: OG_IMAGE.height,
alt: OG_IMAGE.alt,
url: ogImageUrl(TITLE, OG_DESCRIPTION),
width: 1200,
height: 630,
alt: TITLE,
},
],
locale: SEO.locale,
Expand All @@ -51,7 +52,7 @@ export const metadata: Metadata = {
card: SEO.twitterCard,
title: TITLE,
description: DESCRIPTION,
images: [OG_IMAGE.url],
images: [ogImageUrl(TITLE, OG_DESCRIPTION)],
},
keywords: [...SEO.keywords, "cloud", "subscription", "cloud agents", "AI cloud development"],
}
Expand Down
15 changes: 8 additions & 7 deletions apps/web-roo-code/src/app/enterprise/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ import { ContactForm } from "@/components/enterprise/contact-form"
import { EXTERNAL_LINKS } from "@/lib/constants"
import type { Metadata } from "next"
import { SEO } from "@/lib/seo"
import { ogImageUrl } from "@/lib/og"

const TITLE = "Enterprise Solution"
const TITLE = "Roo Code Cloud Enterprise"
const DESCRIPTION =
"The control-plane for AI-powered software development. Gain visibility, governance, and control over your AI coding initiatives."
const OG_DESCRIPTION = "The control-plane for AI-powered software development"
const PATH = "/enterprise"
const OG_IMAGE = SEO.ogImage

export const metadata: Metadata = {
title: TITLE,
Expand All @@ -27,10 +28,10 @@ export const metadata: Metadata = {
siteName: SEO.name,
images: [
{
url: OG_IMAGE.url,
width: OG_IMAGE.width,
height: OG_IMAGE.height,
alt: OG_IMAGE.alt,
url: ogImageUrl(TITLE, OG_DESCRIPTION),
width: 1200,
height: 630,
alt: TITLE,
},
],
locale: SEO.locale,
Expand All @@ -40,7 +41,7 @@ export const metadata: Metadata = {
card: SEO.twitterCard,
title: TITLE,
description: DESCRIPTION,
images: [OG_IMAGE.url],
images: [ogImageUrl(TITLE, OG_DESCRIPTION)],
},
keywords: [
...SEO.keywords,
Expand Down
19 changes: 11 additions & 8 deletions apps/web-roo-code/src/app/evals/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { Metadata } from "next"

import { getEvalRuns } from "@/actions/evals"
import { SEO } from "@/lib/seo"
import { ogImageUrl } from "@/lib/og"

import { Evals } from "./evals"

Expand All @@ -10,13 +11,8 @@ export const dynamic = "force-dynamic"

const TITLE = "Evals"
const DESCRIPTION = "Explore quantitative evals of LLM coding skills across tasks and providers."
const OG_DESCRIPTION = "Quantitative evals of LLM coding skills"
const PATH = "/evals"
const IMAGE = {
url: "https://i.imgur.com/ijP7aZm.png",
width: 1954,
height: 1088,
alt: "Roo Code Evals – LLM coding benchmarks",
}

export const metadata: Metadata = {
title: TITLE,
Expand All @@ -29,15 +25,22 @@ export const metadata: Metadata = {
description: DESCRIPTION,
url: `${SEO.url}${PATH}`,
siteName: SEO.name,
images: [IMAGE],
images: [
{
url: ogImageUrl(TITLE, OG_DESCRIPTION),
width: 1200,
height: 630,
alt: TITLE,
},
],
locale: SEO.locale,
type: "website",
},
twitter: {
card: SEO.twitterCard,
title: TITLE,
description: DESCRIPTION,
images: [IMAGE.url],
images: [ogImageUrl(TITLE, OG_DESCRIPTION)],
},
keywords: [...SEO.keywords, "benchmarks", "LLM evals", "coding evaluations", "model comparison"],
}
Expand Down
14 changes: 9 additions & 5 deletions apps/web-roo-code/src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from "react"
import type { Metadata } from "next"
import { Inter } from "next/font/google"
import { SEO } from "@/lib/seo"
import { ogImageUrl } from "@/lib/og"
import { CookieConsentWrapper } from "@/components/CookieConsentWrapper"

import { Providers } from "@/components/providers"
Expand All @@ -12,6 +13,9 @@ import "./globals.css"

const inter = Inter({ subsets: ["latin"] })

const OG_TITLE = "Meet Roo Code"
const OG_DESCRIPTION = "The AI dev team that gets things done."

export const metadata: Metadata = {
metadataBase: new URL(SEO.url),
title: {
Expand Down Expand Up @@ -51,10 +55,10 @@ export const metadata: Metadata = {
siteName: SEO.name,
images: [
{
url: SEO.ogImage.url,
width: SEO.ogImage.width,
height: SEO.ogImage.height,
alt: SEO.ogImage.alt,
url: ogImageUrl(OG_TITLE, OG_DESCRIPTION),
width: 1200,
height: 630,
alt: OG_TITLE,
},
],
locale: SEO.locale,
Expand All @@ -64,7 +68,7 @@ export const metadata: Metadata = {
card: SEO.twitterCard,
title: SEO.title,
description: SEO.description,
images: [SEO.ogImage.url],
images: [ogImageUrl(OG_TITLE, OG_DESCRIPTION)],
},
robots: {
index: true,
Expand Down
15 changes: 8 additions & 7 deletions apps/web-roo-code/src/app/legal/cookies/page.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import type { Metadata } from "next"
import { SEO } from "@/lib/seo"
import { ogImageUrl } from "@/lib/og"

const TITLE = "Cookie Policy"
const TITLE = "Our Cookie Policy"
const DESCRIPTION = "Learn about how Roo Code uses cookies to enhance your experience and provide our services."
const OG_DESCRIPTION = ""
const PATH = "/legal/cookies"
const OG_IMAGE = SEO.ogImage

export const metadata: Metadata = {
title: TITLE,
Expand All @@ -19,10 +20,10 @@ export const metadata: Metadata = {
siteName: SEO.name,
images: [
{
url: OG_IMAGE.url,
width: OG_IMAGE.width,
height: OG_IMAGE.height,
alt: OG_IMAGE.alt,
url: ogImageUrl(TITLE, OG_DESCRIPTION),
width: 1200,
height: 630,
alt: TITLE,
},
],
locale: SEO.locale,
Expand All @@ -32,7 +33,7 @@ export const metadata: Metadata = {
card: SEO.twitterCard,
title: TITLE,
description: DESCRIPTION,
images: [OG_IMAGE.url],
images: [ogImageUrl(TITLE, OG_DESCRIPTION)],
},
keywords: [...SEO.keywords, "cookies", "privacy", "tracking", "analytics"],
}
Expand Down
Loading