diff --git a/data/brand-assets.json b/data/brand-assets.json new file mode 100644 index 00000000..d8f59402 --- /dev/null +++ b/data/brand-assets.json @@ -0,0 +1,116 @@ +{ + "updatedAt": "2026-02-09T21:14:00.000Z", + "colors": [ + { + "id": "primary", + "name": "Primary Cyan", + "hex": "#06D6A0", + "role": "Primary accents, CTA buttons, links" + }, + { + "id": "secondary", + "name": "Secondary Violet", + "hex": "#A78BFA", + "role": "Secondary accents, supporting UI highlights" + }, + { + "id": "accent", + "name": "Bolt Gold", + "hex": "#FBBF24", + "role": "Logo lightning bolt and emphasis moments" + }, + { + "id": "background", + "name": "Midnight Background", + "hex": "#0A0A0A", + "role": "Primary page and app background" + }, + { + "id": "text", + "name": "Cloud Text", + "hex": "#F8FAFC", + "role": "Primary foreground copy and headings" + } + ], + "typography": { + "primary": { + "label": "Primary Font", + "name": "Space Grotesk", + "family": "var(--font-space-grotesk)", + "weights": [400, 500, 600, 700], + "sample": "Built by agents, for agents" + }, + "secondary": { + "label": "Secondary Font", + "name": "Inter", + "family": "Inter, system-ui, -apple-system, sans-serif", + "weights": [400, 500, 600], + "sample": "Fast, readable product copy" + }, + "monospace": { + "label": "Monospace Font", + "name": "JetBrains Mono", + "family": "var(--font-jetbrains-mono)", + "weights": [400, 700], + "sample": "GET /api/brand" + } + }, + "logos": [ + { + "id": "full", + "name": "Full Logo", + "description": "Icon + wordmark lockup for most marketing surfaces", + "url": "https://cdn.foragents.dev/brand/foragents-full.svg", + "width": 1600, + "height": 480, + "fileType": "SVG", + "background": "dark" + }, + { + "id": "icon", + "name": "Icon Mark", + "description": "Lightning bolt icon for avatars, favicons, and compact UI", + "url": "https://cdn.foragents.dev/brand/foragents-icon.svg", + "width": 512, + "height": 512, + "fileType": "SVG", + "background": "transparent" + }, + { + "id": "wordmark", + "name": "Wordmark", + "description": "Text-only lockup for constrained horizontal layouts", + "url": "https://cdn.foragents.dev/brand/foragents-wordmark.svg", + "width": 1200, + "height": 240, + "fileType": "SVG", + "background": "dark" + }, + { + "id": "dark", + "name": "Dark Background Variant", + "description": "Optimized export for dark hero sections and presentations", + "url": "https://cdn.foragents.dev/brand/foragents-dark.png", + "width": 2400, + "height": 900, + "fileType": "PNG", + "background": "dark" + } + ], + "guidelines": { + "dos": [ + "Maintain at least 16px of clear space around the logo.", + "Use the bolt gold accent (#FBBF24) for the lightning symbol.", + "Prefer dark backgrounds for highest contrast and brand consistency.", + "Scale logo assets proportionally from original files.", + "Use provided SVG files for digital and web placements." + ], + "donts": [ + "Do not recolor the logo or apply gradient overlays.", + "Do not stretch, skew, or rotate logo variants.", + "Do not place logos on busy backgrounds that hurt legibility.", + "Do not add drop shadows, outlines, or glow effects.", + "Do not rebuild the wordmark with substitute typefaces." + ] + } +} diff --git a/src/app/api/brand/route.ts b/src/app/api/brand/route.ts new file mode 100644 index 00000000..2141fd3b --- /dev/null +++ b/src/app/api/brand/route.ts @@ -0,0 +1,67 @@ +import { promises as fs } from "node:fs"; +import path from "node:path"; +import { NextResponse } from "next/server"; + +export const runtime = "nodejs"; + +const BRAND_ASSETS_PATH = path.join(process.cwd(), "data", "brand-assets.json"); + +type BrandColor = { + id: string; + name: string; + hex: string; + role: string; +}; + +type BrandFont = { + label: string; + name: string; + family: string; + weights: number[]; + sample: string; +}; + +type BrandLogo = { + id: string; + name: string; + description: string; + url: string; + width: number; + height: number; + fileType: string; + background: string; +}; + +type BrandGuidelines = { + dos: string[]; + donts: string[]; +}; + +type BrandAssets = { + updatedAt: string; + colors: BrandColor[]; + typography: { + primary: BrandFont; + secondary: BrandFont; + monospace: BrandFont; + }; + logos: BrandLogo[]; + guidelines: BrandGuidelines; +}; + +async function readBrandAssets(): Promise { + const raw = await fs.readFile(BRAND_ASSETS_PATH, "utf8"); + return JSON.parse(raw) as BrandAssets; +} + +export async function GET() { + try { + const data = await readBrandAssets(); + return NextResponse.json(data, { + headers: { "Cache-Control": "public, max-age=300" }, + }); + } catch (error) { + console.error("Failed to load brand assets", error); + return NextResponse.json({ error: "Failed to load brand assets" }, { status: 500 }); + } +} diff --git a/src/app/brand/brand-client.tsx b/src/app/brand/brand-client.tsx new file mode 100644 index 00000000..042edbdb --- /dev/null +++ b/src/app/brand/brand-client.tsx @@ -0,0 +1,340 @@ +/* eslint-disable react/no-unescaped-entities */ +"use client"; + +import { useEffect, useMemo, useState } from "react"; +import Link from "next/link"; +import { Badge } from "@/components/ui/badge"; +import { Button } from "@/components/ui/button"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { Separator } from "@/components/ui/separator"; + +type BrandColor = { + id: string; + name: string; + hex: string; + role: string; +}; + +type BrandFont = { + label: string; + name: string; + family: string; + weights: number[]; + sample: string; +}; + +type BrandLogo = { + id: string; + name: string; + description: string; + url: string; + width: number; + height: number; + fileType: string; + background: string; +}; + +type BrandAssets = { + updatedAt: string; + colors: BrandColor[]; + typography: { + primary: BrandFont; + secondary: BrandFont; + monospace: BrandFont; + }; + logos: BrandLogo[]; + guidelines: { + dos: string[]; + donts: string[]; + }; +}; + +function LoadingState() { + return ( +
+
+
+
+
+
+
+ ); +} + +function ErrorState({ message, onRetry }: { message: string; onRetry: () => void }) { + return ( +
+ + + Couldn't load brand assets + + +

{message}

+ +
+
+
+ ); +} + +export function BrandClientPage() { + const [data, setData] = useState(null); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + const [copiedColor, setCopiedColor] = useState(null); + const [downloadingId, setDownloadingId] = useState(null); + const [downloadedIds, setDownloadedIds] = useState([]); + + const fetchBrandData = async () => { + setLoading(true); + setError(null); + + try { + const response = await fetch("/api/brand", { cache: "no-store" }); + if (!response.ok) { + throw new Error("Unexpected server response"); + } + + const payload = (await response.json()) as BrandAssets; + setData(payload); + } catch { + setError("The brand API is currently unavailable. Please retry."); + } finally { + setLoading(false); + } + }; + + useEffect(() => { + void fetchBrandData(); + }, []); + + const fonts = useMemo(() => { + if (!data) return []; + return Object.values(data.typography); + }, [data]); + + const copyHex = async (hex: string) => { + try { + await navigator.clipboard.writeText(hex); + setCopiedColor(hex); + window.setTimeout(() => setCopiedColor(null), 1400); + } catch { + setCopiedColor(null); + } + }; + + const simulateDownload = (logoId: string) => { + setDownloadingId(logoId); + + window.setTimeout(() => { + setDownloadingId(null); + setDownloadedIds((current) => (current.includes(logoId) ? current : [...current, logoId])); + }, 900); + }; + + if (loading) return ; + if (error || !data) return ; + + return ( +
+
+ + Live press kit data + +

Brand Guidelines

+

+ Logos, color palette, typography, and usage guidance sourced from persistent JSON data. +

+
+ + + +
+
+

Color Swatches

+

Click copy to grab exact hex values for implementation.

+
+ +
+ {data.colors.map((color) => ( + +
+ +
+

{color.name}

+

{color.role}

+
+
+ {color.hex} + +
+
+ + ))} +
+
+ + + +
+
+

Typography

+

Primary, secondary, and monospace font guidance.

+
+ +
+ {fonts.map((font) => ( + + + {font.label} + + +
+

{font.name}

+

Weights: {font.weights.join(", ")}

+
+
+ {font.sample} +
+
+
+ ))} +
+
+ + + +
+
+

Logo Variants

+

4 standard variants with dimensions and quick download simulation.

+
+ +
+ {data.logos.map((logo) => { + const isDownloading = downloadingId === logo.id; + const downloaded = downloadedIds.includes(logo.id); + + return ( + + + {logo.name} + + +
+

{logo.description}

+

+ {logo.width}×{logo.height}px · {logo.fileType} · {logo.background} background +

+
+ +
+ + + View file URL + +
+ + {downloaded ?

Download ready: {logo.name}

: null} +
+
+ ); + })} +
+
+ + + +
+
+

Usage Guidelines

+

5 do's and don'ts for consistent brand usage.

+
+ +
+ + + Do + + +
    + {data.guidelines.dos.map((rule) => ( +
  • + + {rule} +
  • + ))} +
+
+
+ + + + Don't + + +
    + {data.guidelines.donts.map((rule) => ( +
  • + + {rule} +
  • + ))} +
+
+
+
+
+ + + +
+

+ Last updated: {new Date(data.updatedAt).toLocaleString()} +

+
+ + Press inquiries + + + Contribute updates + +
+
+
+ ); +} diff --git a/src/app/brand/page.tsx b/src/app/brand/page.tsx index a7b1f902..c809c3c1 100644 --- a/src/app/brand/page.tsx +++ b/src/app/brand/page.tsx @@ -1,15 +1,12 @@ -import Link from "next/link"; -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; -import { Badge } from "@/components/ui/badge"; -import { Separator } from "@/components/ui/separator"; -import { ColorSwatch } from "@/components/color-swatch"; +import { Metadata } from "next"; +import { BrandClientPage } from "./brand-client"; -export const metadata = { +export const metadata: Metadata = { title: "Brand Guidelines — forAgents.dev", - description: "Logo usage, color palette, typography, and brand voice guidelines for forAgents.dev", + description: "Logo usage, color palette, typography, and press kit resources for forAgents.dev", openGraph: { title: "Brand Guidelines — forAgents.dev", - description: "Logo usage, color palette, typography, and brand voice guidelines for forAgents.dev", + description: "Logo usage, color palette, typography, and press kit resources for forAgents.dev", url: "https://foragents.dev/brand", siteName: "forAgents.dev", type: "website", @@ -17,590 +14,5 @@ export const metadata = { }; export default function BrandPage() { - const colors = [ - { - name: "Primary Cyan", - hex: "#06D6A0", - description: "Main brand accent color", - usage: "CTAs, links, highlights", - }, - { - name: "Background Dark", - hex: "#0a0a0a", - description: "Primary background", - usage: "Page backgrounds, dark sections", - }, - { - name: "Foreground Light", - hex: "#F8FAFC", - description: "Primary text color", - usage: "Headings, body text", - }, - { - name: "Muted", - hex: "#94A3B8", - description: "Secondary text", - usage: "Descriptions, metadata", - }, - { - name: "Purple Accent", - hex: "#A78BFA", - description: "Secondary accent", - usage: "Gradients, decorative elements", - }, - { - name: "Yellow Accent", - hex: "#FBBF24", - description: "Logo lightning bolt", - usage: "Logo, energy indicators", - }, - ]; - - const typographyScale = [ - { name: "Display", size: "56px", weight: "700", usage: "Hero headlines" }, - { name: "Heading 1", size: "40px", weight: "700", usage: "Page titles" }, - { name: "Heading 2", size: "32px", weight: "600", usage: "Section headers" }, - { name: "Heading 3", size: "24px", weight: "600", usage: "Sub-sections" }, - { name: "Body Large", size: "18px", weight: "400", usage: "Lead paragraphs" }, - { name: "Body", size: "16px", weight: "400", usage: "Main content" }, - { name: "Small", size: "14px", weight: "400", usage: "Captions, metadata" }, - { name: "Code", size: "14px", weight: "400", usage: "Code snippets (JetBrains Mono)" }, - ]; - - return ( -
- {/* Hero Section */} -
- {/* Subtle aurora background */} -
-
-
-
- -
-

- Brand Guidelines -

-

- Logo usage, colors, typography, and voice for forAgents.dev -

-
-
- - - - {/* Logo Section */} - - - - - {/* Color Palette Section */} -
-
-

🎨 Color Palette

-

- Our color system is optimized for dark interfaces and high contrast -

-
- -
- {colors.map((color) => ( - - ))} -
- -
-

- 💡 - Accessibility Note -

-

- All color combinations meet WCAG AA standards for contrast. Primary cyan (#06D6A0) on dark backgrounds provides excellent readability and visual hierarchy. -

-
-
- - - - {/* Typography Section */} -
-
-

✍️ Typography

-

- We use Space Grotesk for UI and JetBrains Mono for code -

-
- -
- {/* Font Families */} -
- - - Space Grotesk - - -

- Primary font for headings, body text, and UI elements -

-
-
The quick brown fox
-
The quick brown fox
-
The quick brown fox
-
The quick brown fox
-
-
-

- Weights: 400 (Regular), 500 (Medium), 600 (Semibold), 700 (Bold) -

-
-
-
- - - - JetBrains Mono - - -

- Monospace font for code, technical content, and data -

-
- - const agent = "Link" - - - fetch('/api/skills') - - - GET /llms.txt - -
-
-

- Weights: 400 (Regular), 700 (Bold) -

-
-
-
-
- - {/* Type Scale */} - - - Type Scale - - -
- {typographyScale.map((item) => ( -
-
-

{item.name}

-

- {item.size} / {item.weight} -

-
-
- {item.name === "Code" ? "sample_code()" : "Sample Text"} -
-
- {item.usage} -
-
- ))} -
-
-
-
-
- - - - {/* Brand Voice Section */} -
-
-

🗣️ Brand Voice

-

- How we communicate with agents and humans alike -

-
- -
- - - - - We Are - - - -
    -
  • - -
    - Direct -

    - No fluff. Skip the marketing speak. Get to the point. -

    -
    -
  • -
  • - -
    - Technical -

    - We speak to builders. Code samples, APIs, and markdown matter. -

    -
    -
  • -
  • - -
    - Honest -

    - If something's in beta, we say so. If it's broken, we fix it. -

    -
    -
  • -
  • - -
    - Playful -

    - Agents are cool. Building infrastructure for them should be fun. -

    -
    -
  • -
-
-
- - - - - 🚫 - We Avoid - - - -
    -
  • - -
    - Corporate Jargon -

    - No "synergy," "leverage," or "paradigm shifts." -

    -
    -
  • -
  • - -
    - Hype -

    - We don't claim to be "revolutionary" or "game-changing." -

    -
    -
  • -
  • - -
    - Gatekeeping -

    - Agent development is for everyone. No elitism. -

    -
    -
  • -
  • - -
    - Vagueness -

    - If we can't explain it clearly, we don't ship it. -

    -
    -
  • -
-
-
-
- - {/* Voice Examples */} - - - Examples - - -
-
-
- - Good - - Headlines -
-
-

- "Built by agents, for agents" -

-

- "News, skills, and signal. Served as markdown." -

-
-
- -
-
- - Good - - CTAs -
-
-

- "Browse Skills →" -

-

- "GET /api/feed.md" -

-
-
- -
-
- - Avoid - - What not to say -
-
-

- "Revolutionizing the agent ecosystem" -

-

- "Unlock the power of AI-driven synergy" -

-
-
-
-
-
-
- - - - {/* Download Assets Section */} -
-
-

📦 Download Assets

-

- Get logo files, color palettes, and brand resources -

-
- -
-
-
- -
-
- 📦 -

Brand Assets Package

-
- -

- Download our complete brand package including SVG logos, PNG exports, color palettes in multiple formats, and typography guidelines. Perfect for partners, press, and community projects. -

- -
-
- - Logo (SVG, PNG, ICO) -
-
- - Color swatches -
-
- - Typography guide -
-
- -
- - - Contact for Custom Needs → - -
-
-
-
- -
- ); + return ; }