import { ArrowRight, Search } from 'lucide-react'; import type { Metadata } from 'next'; import Link from 'next/link'; import { ChangeRow } from '@/components/changes/change-row'; import { Sparkline, TimelineLanes } from '@/components/charts'; import { DataStrip, type StripItem, Ticker, type TickerItem } from '@/components/layout/terminal'; import { EntityBadge, OpennessBadge } from '@/components/ui/badges'; import { EntityLink } from '@/components/ui/entity'; import { LiveAgo } from '@/components/ui/live'; import { Container, Section } from '@/components/ui/section'; import { Unavailable } from '@/components/ui/unavailable'; import { api, safe } from '@/lib/api'; import { fmtDate, fmtDeltaPct, fmtInt, fmtParams, fmtScore, fmtTokens, fmtUsdPerM, hostOf, num } from '@/lib/format'; import { DESCRIPTION, EXAMPLE_QUERIES, eventTone, routes, signatureProducts, SITE_NAME, TAGLINE } from '@/lib/site'; import type { ChangeEvent, EntitySummary } from '@/lib/types'; export const metadata: Metadata = { title: { absolute: `${SITE_NAME} — ${TAGLINE}` }, description: DESCRIPTION, alternates: { canonical: '/' }, }; export const revalidate = 60; /** Fallback "How counted" texts — replaced by `stats.definitions` when the API provides them. */ const DEFINITIONS: Record = { model: 'Entities typed “model” in the graph. After canonicalisation: canonical model releases only — artifacts (quantizations, conversions) and folded evaluation variants are excluded.', organization: 'Companies, labs, universities and other organizations (entity types company · organization · lab · university).', paper: 'Research papers ingested from arXiv and publisher feeds (one entity per paper, deduplicated by identifier).', dataset: 'Datasets known to the graph (Hugging Face and publisher pages).', benchmark_results: 'Live benchmark result rows (one per model × benchmark × metric × configuration). Superseded runs are closed, never deleted.', provider: 'API providers that serve models (each with its own model listing and prices).', prices_current: 'Price offers currently valid (USD per 1M tokens) across all providers — one live row per model × provider × provider model id.', documents: 'Source documents crawled by first-party connectors; every fact links back to one of them (snapshots are archived forever).', }; const OPEN_EVENT_TYPES = new Set(['NEW_MODEL', 'RELEASE', 'VERSION_RELEASED']); function occurredAt(e: ChangeEvent): string { return e.effective_at ?? e.observed_at; } function priceMove(e: ChangeEvent): { input: [number | null, number | null]; output: [number | null, number | null] } { const o = (e.old_value && typeof e.old_value === 'object' ? e.old_value : {}) as Record; const n = (e.new_value && typeof e.new_value === 'object' ? e.new_value : {}) as Record; return { input: [num(o.input_per_mtok), num(n.input_per_mtok)], output: [num(o.output_per_mtok), num(n.output_per_mtok)] }; } /** Deterministic pseudo-random constellation for the graph teaser (decorative; the numbers beside it are real). */ function constellation(seed: number, n: number): { x: number; y: number; t: number; r: number }[] { let s = seed; const rnd = () => { s = (s * 1103515245 + 12345) & 0x7fffffff; return s / 0x7fffffff; }; return Array.from({ length: n }, () => ({ x: 8 + rnd() * 304, y: 8 + rnd() * 144, t: Math.floor(rnd() * 6), r: 1.2 + rnd() * 2.2 })); } const NODE_TYPES = ['model', 'company', 'paper', 'provider', 'benchmark', 'hardware']; export default async function HomePage() { const [stats, daily, frontier, majors, priceIndex, open, openFallback, benchmarks, papers, timeline, recent] = await Promise.all([ safe(api.stats()), safe(api.changesDaily()), safe(api.frontier()), safe(api.changes({ importance_min: 3, limit: 8 })), safe(api.priceIndex(30)), safe(api.open(30, 8)), safe(api.models({ openness: 'open-weights', sort: 'release', limit: 8 })), safe(api.benchmarks()), safe(api.papers({ sort: 'published', limit: 6 })), safe(api.timeline({ category: 'model', limit: 400 })), safe(api.changes({ importance_min: 2, limit: 30 })), ]); const ent = stats?.entities ?? {}; const orgs = stats ? (num(ent.company) ?? 0) + (num(ent.organization) ?? 0) + (num(ent.lab) ?? 0) + (num(ent.university) ?? 0) : null; const defs = { ...DEFINITIONS, ...(stats?.definitions ?? {}) }; const live24 = num(stats?.change_events_live_24h); const strip: StripItem[] | null = stats ? [ { label: 'Models', value: fmtInt(ent.model), href: routes.models(), definition: defs.model }, { label: 'Organizations', value: fmtInt(orgs), href: routes.companies(), definition: defs.organization }, { label: 'Papers', value: fmtInt(ent.paper), href: routes.papers(), definition: defs.paper }, { label: 'Datasets', value: fmtInt(ent.dataset), href: routes.datasets(), definition: defs.dataset }, { label: 'Benchmark results', value: fmtInt(stats.benchmark_results), href: routes.benchmarks(), definition: defs.benchmark_results }, { label: 'Providers', value: fmtInt(ent.provider), href: routes.providers(), definition: defs.provider }, { label: 'Current prices', value: fmtInt(stats.prices_current), href: routes.prices(), definition: defs.prices_current }, { label: 'Source documents', value: fmtInt(stats.documents), href: routes.sources(), definition: defs.documents, hint: `${fmtInt(stats.sources)} sources` }, ] : null; // ---- today const today = daily?.date ?? new Date().toISOString().slice(0, 10); const sections = (daily?.sections ?? []).filter((s) => s.items.length > 0).slice(0, 6); const todayTotal = num(daily?.total) ?? Object.values(daily?.counts ?? {}).reduce((n, v) => n + (num(v) ?? 0), 0); // ---- frontier moves const frontierMoves: ChangeEvent[] = frontier?.recent_frontier_movements?.length ? frontier.recent_frontier_movements.slice(0, 6) : (majors?.items ?? []).slice(0, 6); const frontierLive = !!frontier?.recent_frontier_movements?.length; // ---- prices const movers = (priceIndex?.movers ?? []).filter((e) => e.event_type === 'PRICE_CHANGED').slice(0, 7); const medianSeries = (priceIndex?.series ?? []).map((p) => num(p.median_input)).filter((v): v is number => v !== null); const medianLast = medianSeries.length ? (medianSeries[medianSeries.length - 1] as number) : null; // ---- open models const openItems: EntitySummary[] = open?.items?.length ? open.items.slice(0, 8) : (openFallback?.items ?? []).slice(0, 8); const openLive = !!open?.items?.length; // ---- benchmarks const leaders = (benchmarks?.items ?? []) .filter((b) => b.top && (num(b.result_count) ?? 0) > 0) .sort((a, b) => (num(b.model_count) ?? 0) - (num(a.model_count) ?? 0)) .slice(0, 6); // ---- release timeline (last 12 months, NEW_MODEL / RELEASE, importance ≥ 2), lanes = top organizations const since = Date.now() - 365 * 86400000; const releaseEvents = (timeline?.items ?? []) .flatMap((m) => m.events) .filter((e) => OPEN_EVENT_TYPES.has(e.event_type) && e.importance >= 2 && e.entity && new Date(occurredAt(e)).getTime() >= since); const orgCount = new Map(); for (const e of releaseEvents) orgCount.set(e.entity?.organization?.name ?? 'Other', (orgCount.get(e.entity?.organization?.name ?? 'Other') ?? 0) + 1); const topOrgs = [...orgCount.entries()] .filter(([k]) => k !== 'Other') .sort((a, b) => b[1] - a[1]) .slice(0, 7) .map(([k]) => k); const lanes = [...topOrgs.map((k, i) => ({ key: k, label: k, color: `var(--series-${(i % 8) + 1})` })), ...(orgCount.size > topOrgs.length ? [{ key: 'Other', label: 'Other', color: 'var(--ink-3)' }] : [])]; const laneEvents = releaseEvents.map((e) => { const org = e.entity?.organization?.name ?? 'Other'; return { id: e.id, lane: topOrgs.includes(org) ? org : 'Other', at: occurredAt(e), importance: e.importance, label: e.entity?.name ?? e.summary, sub: e.summary, href: e.entity ? routes.entity(e.entity) : undefined }; }); // ---- ticker const ticker: TickerItem[] = (recent?.items ?? []).slice(0, 24).map((e) => ({ id: e.id, tone: eventTone(e.event_type), href: e.entity ? routes.entity(e.entity) : routes.changes(), label: e.summary.length > 90 ? `${e.summary.slice(0, 89)}…` : e.summary, meta: fmtDate(occurredAt(e)) })); const nodes = constellation(20260912, 42); return ( <> {/* ------------------------------------------------------------------------------------------------ hero (compact) */}

The temporal knowledge graph of the AI ecosystem

Explore the AI ecosystem.

Not a directory — a continuously reconstructed, source-attributed, historical map of models, organizations, research, providers and prices, benchmarks, hardware and datasets.

Every number here answers: who said it, when, where, and how it was extracted.

    {EXAMPLE_QUERIES.map((q) => (
  • {q}
  • ))}
  • or press ⌘K
{/* ------------------------------------------------------------------------------------------------ live strip */}

Live ecosystem {stats && ( computed {live24 !== null && · {fmtInt(live24)} live events / 24 h} )}

How counts are computed →
{strip ? : }
{ticker.length > 0 && } {/* ------------------------------------------------------------------------------------------------ editorial grid */}
{/* today */}
{sections.length ? (
{sections.map((s) => (

{s.label} {fmtInt(num(s.total) ?? num(daily?.counts?.[s.category]) ?? s.items.length)}

    {s.items.slice(0, 5).map((e) => ( ))}
))}
) : daily ? (

No material events recorded today yet. The change engine only emits events when a source states a material change.

) : ( )}

{daily?.backfill_excluded !== undefined ? ( <> {fmtInt(daily.backfill_excluded)} historical backfill events are excluded — see the Timeline. ) : ( <> Digest keyed on observation time; historical backfill is shown on the Timeline by effective date. )}

{/* frontier moves */}
{frontierMoves.length ? (
    {frontierMoves.map((e) => ( ))}
) : majors ? (

No major events recorded yet.

) : ( )}
{/* benchmark leaders */}
{leaders.length ? (
    {leaders.map((b) => (
  • {typeof b.attributes?.metric === 'string' && {b.attributes.metric}}

    leader {b.top!.model.organization && · {b.top!.model.organization.name}}

    {fmtInt(b.result_count)} results · {fmtInt(b.model_count)} models {typeof b.attributes?.trust_level === 'string' ? <> · trust {b.attributes.trust_level} : <> · trust —}

    {fmtScore(b.top!.score)}

  • ))}
) : benchmarks ? (

No benchmark results ingested yet.

) : ( )}
{/* price moves */}

Median input · 30 d

{medianSeries.length >= 2 ? ( fmtUsdPerM(v)} title="Median input price, last 30 days" /> ) : (

{medianLast !== null ? `${fmtUsdPerM(medianLast)} today · ` : ''}needs ≥ 2 daily snapshots to draw

)}

{stats ? <>{fmtInt(stats.prices_current)} live offers : null}
{priceIndex?.series?.length ? <>{fmtInt(priceIndex.series[priceIndex.series.length - 1]?.models)} models priced : null}

{movers.length ? (
    {movers.map((e) => { const m = priceMove(e); const dIn = fmtDeltaPct(m.input[0], m.input[1]); const dOut = fmtDeltaPct(m.output[0], m.output[1]); const provider = hostOf(e.source_url); return (
  • {e.entity ? : {e.summary}}

    {provider ?? e.connector_name} · {fmtDate(occurredAt(e))}

    in {fmtUsdPerM(m.input[1])} {dIn && {dIn}}

    out {fmtUsdPerM(m.output[1])} {dOut && {dOut}}

  • ); })}
) : priceIndex ? (

No price changes recorded in the window.

) : ( )}
{/* open models */}
{openItems.length ? (
    {openItems.map((m) => { const a = m.attributes ?? {}; return (
  • {m.organization && · {m.organization.name}}

    {num(a.parameter_count) !== null && <>{fmtParams(a.parameter_count)} params · } {num(a.context_length) !== null && <>{fmtTokens(a.context_length)} ctx · } {typeof a.license === 'string' ? a.license : 'license —'}

    {typeof a.release_date === 'string' ? fmtDate(a.release_date) : '—'}

  • ); })}
) : openFallback || open ? (

No open-weight releases recorded in the window.

) : ( )}
{/* research */}
{papers?.items?.length ? (
    {papers.items.slice(0, 6).map((p) => { const a = p.attributes ?? {}; const authors = Array.isArray(a.authors) ? (a.authors as string[]) : []; return (
  • {typeof a.published_at === 'string' && <>{fmtDate(a.published_at)} · } {authors.length > 0 && <>{authors.slice(0, 2).join(', ')}{authors.length > 2 ? ` +${authors.length - 2}` : ''} · } {typeof a.arxiv_id === 'string' && arXiv {a.arxiv_id}} {typeof a.primary_category === 'string' && <> · {a.primary_category}}

  • ); })}
) : papers ? (

No papers ingested yet.

) : ( )}
{/* ------------------------------------------------------------------------------------------------ release timeline */}
{laneEvents.length >= 2 && lanes.length ? ( ) : timeline ? (

Not enough dated release events in the last 12 months to draw a timeline.

) : ( )}
{/* ------------------------------------------------------------------------------------------------ graph teaser */}

{stats ? fmtInt(stats.entities_total) : '—'} entities · {stats ? fmtInt(stats.relations) : '—'} relations

Organizations develop models, providers serve them, papers describe them, benchmarks evaluate them, hardware runs them. Start from any entity and follow the edges — lineage, ownership, availability — with the source of every relation.

Knowledge graph → Model families → Compare →

{nodes.map((n, i) => nodes.slice(i + 1, i + 3).map((m, j) => ( )), )} {nodes.map((n, i) => ( ))}

{NODE_TYPES.map((t) => ( ))}

{/* ------------------------------------------------------------------------------------------------ signature products */}
    {signatureProducts.map((p) => (
  • {p.label}

    {p.hint &&

    {p.hint}

    }
  • ))}
); }