diff --git a/components/NotFoundAnimation.tsx b/components/NotFoundAnimation.tsx index 487d82a484..db736e7b76 100644 --- a/components/NotFoundAnimation.tsx +++ b/components/NotFoundAnimation.tsx @@ -1,11 +1,6 @@ "use client"; import dynamic from "next/dynamic"; -import { Canvas, useFrame } from "@react-three/fiber"; -import { TrackballControls, Environment } from "@react-three/drei"; -import { useRef, useState } from "react"; -import * as THREE from "three"; -import { useTheme } from "next-themes"; const CANVAS_STYLES = { width: "100%", @@ -14,83 +9,14 @@ const CANVAS_STYLES = { maxHeight: "600px", } as const; -function MetallicKnot() { - const meshRef = useRef(null); - const { resolvedTheme } = useTheme(); - - useFrame((state) => { - if (meshRef.current) { - meshRef.current.rotation.x = state.clock.elapsedTime * 0.25; - meshRef.current.rotation.y = state.clock.elapsedTime * 0.2; - meshRef.current.rotation.z = state.clock.elapsedTime * 0.15; - } - }); - - return ( - - - - - ); -} - -function NotFoundAnimationComponent() { - const [canvasKey, setCanvasKey] = useState(0); - - return ( - { - gl.domElement.addEventListener("webglcontextlost", (e) => { - e.preventDefault(); - // If the context isn't restored within 2 s, force a full remount - setTimeout(() => setCanvasKey((k) => k + 1), 2000); - }); - }} - > - - - - - - - - - ); -} - +// Real dynamic import: the three.js / @react-three modules only load when this +// component renders, so they stay out of the shared/root chunk. (Using +// `Promise.resolve(Component)` here does NOT split the bundle — it just delays +// rendering.) export const NotFoundAnimation = dynamic( - () => Promise.resolve(NotFoundAnimationComponent), + () => import("./NotFoundAnimationImpl"), { ssr: false, loading: () =>
, } -); \ No newline at end of file +); diff --git a/components/NotFoundAnimationImpl.tsx b/components/NotFoundAnimationImpl.tsx new file mode 100644 index 0000000000..77a0c490f2 --- /dev/null +++ b/components/NotFoundAnimationImpl.tsx @@ -0,0 +1,87 @@ +"use client"; + +import { Canvas, useFrame } from "@react-three/fiber"; +import { TrackballControls, Environment } from "@react-three/drei"; +import { useRef, useState } from "react"; +import * as THREE from "three"; +import { useTheme } from "next-themes"; + +const CANVAS_STYLES = { + width: "100%", + height: "50vh", + minHeight: "400px", + maxHeight: "600px", +} as const; + +function MetallicKnot() { + const meshRef = useRef(null); + const { resolvedTheme } = useTheme(); + + useFrame((state) => { + if (meshRef.current) { + meshRef.current.rotation.x = state.clock.elapsedTime * 0.25; + meshRef.current.rotation.y = state.clock.elapsedTime * 0.2; + meshRef.current.rotation.z = state.clock.elapsedTime * 0.15; + } + }); + + return ( + + + + + ); +} + +export default function NotFoundAnimationComponent() { + const [canvasKey, setCanvasKey] = useState(0); + + return ( + { + gl.domElement.addEventListener("webglcontextlost", (e) => { + e.preventDefault(); + // If the context isn't restored within 2 s, force a full remount + setTimeout(() => setCanvasKey((k) => k + 1), 2000); + }); + }} + > + + + + + + + + + ); +} diff --git a/components/home/AllTheTools.tsx b/components/home/AllTheTools.tsx index 8e753c2ca1..2759ebedf0 100644 --- a/components/home/AllTheTools.tsx +++ b/components/home/AllTheTools.tsx @@ -126,11 +126,8 @@ export function AllTheTools() { {tool.title}
@@ -158,11 +155,8 @@ export function AllTheTools() { {tool.title} diff --git a/components/home/feature-tabs/FeatureTabs.tsx b/components/home/feature-tabs/FeatureTabs.tsx index 187c33156b..be9c2e41e2 100644 --- a/components/home/feature-tabs/FeatureTabs.tsx +++ b/components/home/feature-tabs/FeatureTabs.tsx @@ -369,7 +369,6 @@ export const FeatureTabs = ({ src={feature.image.light} alt="" fill - quality={100} sizes="806px" loading={isNext ? "eager" : "lazy"} /> @@ -472,7 +471,6 @@ export const FeatureTabs = ({ alt={mobileFeature?.image.alt} width={1360} height={1640} - quality={100} className="absolute left-0 top-0 min-w-full min-h-full object-cover object-top-left" sizes="(min-width: 640px) 1360px" priority diff --git a/components/home/feature-tabs/TabContent.tsx b/components/home/feature-tabs/TabContent.tsx index 7649cb4aac..40d98b6363 100644 --- a/components/home/feature-tabs/TabContent.tsx +++ b/components/home/feature-tabs/TabContent.tsx @@ -40,7 +40,6 @@ export const TabContent = ({ src={feature.image.light} alt={feature.image.alt} fill - quality={100} className="object-contain object-center sm:object-cover sm:object-top-left dark:hidden" sizes={sizes} priority={priority} @@ -52,7 +51,6 @@ export const TabContent = ({ src={feature.image.dark} alt={feature.image.alt} fill - quality={100} className="hidden object-contain object-center sm:object-cover sm:object-top-left dark:block" sizes={sizes} priority={priority} diff --git a/components/home/img/rive-mock.png b/components/home/img/rive-mock.png index 1974389470..e0060f15ca 100644 Binary files a/components/home/img/rive-mock.png and b/components/home/img/rive-mock.png differ diff --git a/components/wrapped/Metrics.tsx b/components/wrapped/Metrics.tsx index 30cf8f7aa8..95b108841e 100644 --- a/components/wrapped/Metrics.tsx +++ b/components/wrapped/Metrics.tsx @@ -1,6 +1,7 @@ "use client"; import { useEffect, useRef } from "react"; +import dynamic from "next/dynamic"; import { useInView, useMotionValue, useSpring, motion } from "framer-motion"; import { ListTree, @@ -11,19 +12,22 @@ import { Database, type LucideIcon, } from "lucide-react"; -import { - BarChart, - Bar, - XAxis, - CartesianGrid, - Tooltip, - ResponsiveContainer, - LabelList, -} from "recharts"; import { WrappedSection } from "./components/WrappedSection"; import { WrappedGrid, WrappedGridItem } from "./components/WrappedGrid"; import { SectionHeading } from "./components/SectionHeading"; +// Dynamic import keeps recharts out of every page's initial chunk graph. +// The charts only render on /wrapped, so there's no reason to ship ~100 KB +// brotli of recharts on /, /docs/*, /pricing, etc. +const ConsumptionChart = dynamic( + () => import("./MetricsCharts").then((m) => ({ default: m.ConsumptionChart })), + { ssr: false } +); +const DownloadsChart = dynamic( + () => import("./MetricsCharts").then((m) => ({ default: m.DownloadsChart })), + { ssr: false } +); + interface MetricCardProps { value: number | string; label: string; @@ -234,49 +238,6 @@ const metrics = [ }, ]; -// Monthly actual downloads (calculated from cumulative data) -const downloadData = [ - { month: "Jan", downloads: 1.38 }, - { month: "Feb", downloads: 1.40 }, // 2.78 - 1.38 - { month: "Mar", downloads: 1.60 }, // 4.38 - 2.78 - { month: "Apr", downloads: 1.60 }, // 5.98 - 4.38 - { month: "May", downloads: 2.00 }, // 7.98 - 5.98 - { month: "Jun", downloads: 2.50 }, // 10.48 - 7.98 - { month: "Jul", downloads: 11.80 }, // 22.28 - 10.48 - { month: "Aug", downloads: 11.90 }, // 34.18 - 22.28 - { month: "Sep", downloads: 14.80 }, // 48.98 - 34.18 - { month: "Oct", downloads: 18.10 }, // 67.08 - 48.98 - { month: "Nov", downloads: 23.10 }, // 90.18 - 67.08 - { month: "Dec", downloads: 24.20 }, // 114.38 - 90.18 -]; - -// Relative growth data -const growthData = [ - { month: "Jan", growth: 6.15 }, - { month: "Feb", growth: 6.24 }, - { month: "Mar", growth: 9.40 }, - { month: "Apr", growth: 13.25 }, - { month: "May", growth: 15.66 }, - { month: "Jun", growth: 19.28 }, - { month: "Jul", growth: 30.12 }, - { month: "Aug", growth: 39.76 }, - { month: "Sep", growth: 57.83 }, - { month: "Oct", growth: 63.86 }, - { month: "Nov", growth: 86.75 }, - { month: "Dec", growth: 100.00 }, -]; - -const formatDownloads = (value: number) => { - if (value >= 1000) { - return `${(value / 1000).toFixed(1)}M`; - } - return `${value.toFixed(1)}M`; -}; - -const formatGrowth = (value: number) => { - return `${Math.round(value)}%`; -}; - export function Metrics() { const containerRef = useRef(null); const isInView = useInView(containerRef, { once: true, margin: "-100px" }); @@ -338,42 +299,7 @@ export function Metrics() {

Consumption between January and December 2025. Ingestions of traces, observations and evals.

- - - - - [`${formatGrowth(value)}`, "Traffic relative to Dec 25"]} - labelStyle={{ color: "hsl(var(--foreground))" }} - /> - - - - - +
@@ -404,42 +330,7 @@ export function Metrics() {

Monthly Package Downloads

- - - - - [`${formatDownloads(value)}`, "Downloads"]} - labelStyle={{ color: "hsl(var(--foreground))" }} - /> - - - - - +
diff --git a/components/wrapped/MetricsCharts.tsx b/components/wrapped/MetricsCharts.tsx new file mode 100644 index 0000000000..0318231114 --- /dev/null +++ b/components/wrapped/MetricsCharts.tsx @@ -0,0 +1,142 @@ +"use client"; + +import { + BarChart, + Bar, + XAxis, + CartesianGrid, + Tooltip, + ResponsiveContainer, + LabelList, +} from "recharts"; + +// Monthly actual downloads (calculated from cumulative data) +const downloadData = [ + { month: "Jan", downloads: 1.38 }, + { month: "Feb", downloads: 1.40 }, + { month: "Mar", downloads: 1.60 }, + { month: "Apr", downloads: 1.60 }, + { month: "May", downloads: 2.00 }, + { month: "Jun", downloads: 2.50 }, + { month: "Jul", downloads: 11.80 }, + { month: "Aug", downloads: 11.90 }, + { month: "Sep", downloads: 14.80 }, + { month: "Oct", downloads: 18.10 }, + { month: "Nov", downloads: 23.10 }, + { month: "Dec", downloads: 24.20 }, +]; + +// Relative growth data +const growthData = [ + { month: "Jan", growth: 6.15 }, + { month: "Feb", growth: 6.24 }, + { month: "Mar", growth: 9.40 }, + { month: "Apr", growth: 13.25 }, + { month: "May", growth: 15.66 }, + { month: "Jun", growth: 19.28 }, + { month: "Jul", growth: 30.12 }, + { month: "Aug", growth: 39.76 }, + { month: "Sep", growth: 57.83 }, + { month: "Oct", growth: 63.86 }, + { month: "Nov", growth: 86.75 }, + { month: "Dec", growth: 100.00 }, +]; + +const formatDownloads = (value: number) => { + if (value >= 1000) { + return `${(value / 1000).toFixed(1)}M`; + } + return `${value.toFixed(1)}M`; +}; + +const formatGrowth = (value: number) => { + return `${Math.round(value)}%`; +}; + +export function ConsumptionChart() { + return ( + + + + + [ + `${formatGrowth(value)}`, + "Traffic relative to Dec 25", + ]} + labelStyle={{ color: "hsl(var(--foreground))" }} + /> + + + + + + ); +} + +export function DownloadsChart() { + return ( + + + + + [ + `${formatDownloads(value)}`, + "Downloads", + ]} + labelStyle={{ color: "hsl(var(--foreground))" }} + /> + + + + + + ); +} diff --git a/public/images/docs/llm-analytics.png b/public/images/docs/llm-analytics.png index de22b4da8b..1cbfe64894 100644 Binary files a/public/images/docs/llm-analytics.png and b/public/images/docs/llm-analytics.png differ diff --git a/public/images/docs/prompt-management.png b/public/images/docs/prompt-management.png index 5b52aae810..ad2f689ac1 100644 Binary files a/public/images/docs/prompt-management.png and b/public/images/docs/prompt-management.png differ diff --git a/public/images/docs/tracing-overview.png b/public/images/docs/tracing-overview.png index 5a72d8a9f6..42ee4f5235 100644 Binary files a/public/images/docs/tracing-overview.png and b/public/images/docs/tracing-overview.png differ diff --git a/public/images/integrations/helicone_icon.png b/public/images/integrations/helicone_icon.png index ac466c2d2e..0b95ce11dd 100644 Binary files a/public/images/integrations/helicone_icon.png and b/public/images/integrations/helicone_icon.png differ diff --git a/public/images/integrations/inferable_icon.png b/public/images/integrations/inferable_icon.png index 69f0793af6..4969505907 100644 Binary files a/public/images/integrations/inferable_icon.png and b/public/images/integrations/inferable_icon.png differ diff --git a/public/images/integrations/swiftide.png b/public/images/integrations/swiftide.png index 5b03d8f704..e5df4cd97b 100644 Binary files a/public/images/integrations/swiftide.png and b/public/images/integrations/swiftide.png differ diff --git a/public/images/integrations/vertexai_icon.png b/public/images/integrations/vertexai_icon.png index 4ee2b0eb1b..f636d526a3 100644 Binary files a/public/images/integrations/vertexai_icon.png and b/public/images/integrations/vertexai_icon.png differ