diff --git a/bun.lockb b/bun.lockb
index 972b90a46..1e02b7c81 100644
Binary files a/bun.lockb and b/bun.lockb differ
diff --git a/packages/website/package.json b/packages/website/package.json
index 4794fc8d9..30d60d383 100644
--- a/packages/website/package.json
+++ b/packages/website/package.json
@@ -14,6 +14,7 @@
"@nanostores/persistent": "^0.10.2",
"@nanostores/react": "^0.7.3",
"@nivo/bar": "^0.87.0",
+ "@nivo/line": "^0.88.0",
"@radix-ui/colors": "^3.0.0",
"@radix-ui/react-icons": "^1.3.0",
"@radix-ui/themes": "^3.1.4",
diff --git a/packages/website/src/components/Charts/constants.ts b/packages/website/src/components/Charts/constants.ts
new file mode 100644
index 000000000..c5dc4f7c2
--- /dev/null
+++ b/packages/website/src/components/Charts/constants.ts
@@ -0,0 +1 @@
+export const FIRST_AVERAGES_ENTRY = 19925;
diff --git a/packages/website/src/components/Nivo/ThemedLine.tsx b/packages/website/src/components/Nivo/ThemedLine.tsx
new file mode 100644
index 000000000..58614bcdc
--- /dev/null
+++ b/packages/website/src/components/Nivo/ThemedLine.tsx
@@ -0,0 +1,15 @@
+import { ResponsiveLine, type LineSvgProps } from '@nivo/line';
+import { nivoTheme } from '../../core/nivo/theme';
+
+export function ThemedLine(props: LineSvgProps) {
+ return (
+
+ );
+}
diff --git a/packages/website/src/components/Tankopedia/TankopediaCharts.tsx b/packages/website/src/components/Tankopedia/TankopediaCharts.tsx
new file mode 100644
index 000000000..09917090c
--- /dev/null
+++ b/packages/website/src/components/Tankopedia/TankopediaCharts.tsx
@@ -0,0 +1,63 @@
+import { asset, AverageDefinitions } from '@blitzkit/core';
+import { Box, Flex, Heading, Text } from '@radix-ui/themes';
+import { range } from 'lodash-es';
+import { useAveragesExclusionRatio } from '../../hooks/useAveragesExclusionRatio';
+import { Duel } from '../../stores/duel';
+import { FIRST_AVERAGES_ENTRY } from '../Charts/constants';
+import { ThemedLine } from '../Nivo/ThemedLine';
+
+const currentEntry = Math.floor(Date.now() / 1000 / 60 / 60 / 24);
+const days = await Promise.all(
+ range(FIRST_AVERAGES_ENTRY, currentEntry).map(async (day) => {
+ const url = asset(`averages/${day}.pb`);
+ const response = await fetch(url);
+
+ if (response.status !== 200) return null;
+
+ const buffer = await response.arrayBuffer();
+ const averageDefinitions = AverageDefinitions.decode(
+ new Uint8Array(buffer),
+ );
+
+ return { day, definitions: averageDefinitions };
+ }),
+).then((days) => days.filter((day) => day !== null));
+
+export function TankopediaCharts() {
+ const id = Duel.use((state) => state.protagonist.tank.id);
+ const ratio = useAveragesExclusionRatio();
+ const data = days.map(({ day, definitions }) => {
+ const entry = definitions.averages[id];
+ const x = new Date(day * 24 * 60 * 60 * 1000);
+ const y = entry ? Math.round((entry.samples.d_7 / 7) * ratio) : 0;
+
+ return { x, y };
+ });
+
+ return (
+
+
+ Players
+
+ 7-day rolling average
+
+
+
+ {
+ return (date as Date).toLocaleDateString(undefined, {
+ day: 'numeric',
+ month: 'short',
+ year: 'numeric',
+ });
+ }}
+ xScale={{ type: 'time' }}
+ />
+
+
+
+ );
+}
diff --git a/packages/website/src/pages/tools/tankopedia/[id]/_index.tsx b/packages/website/src/pages/tools/tankopedia/[id]/_index.tsx
index 6d0a1c997..ed1ca3be8 100644
--- a/packages/website/src/pages/tools/tankopedia/[id]/_index.tsx
+++ b/packages/website/src/pages/tools/tankopedia/[id]/_index.tsx
@@ -6,6 +6,7 @@ import { GameModeSection } from '../../../../components/Tankopedia/GameModeSecti
import { HeroSection } from '../../../../components/Tankopedia/HeroSection';
import { HistorySection } from '../../../../components/Tankopedia/HistorySection';
import { MetaSection } from '../../../../components/Tankopedia/MetaSection';
+import { TankopediaCharts } from '../../../../components/Tankopedia/TankopediaCharts';
import { TechTreeSection } from '../../../../components/Tankopedia/TechTreeSection';
import { VideoSection } from '../../../../components/Tankopedia/VideoSection';
import { awaitableModelDefinitions } from '../../../../core/awaitables/modelDefinitions';
@@ -48,6 +49,7 @@ export function Page({ id, skeleton }: PageProps) {
)}
+