diff --git a/.github/workflows/publish-benchmarks-website.yml b/.github/workflows/publish-benchmarks-website.yml
deleted file mode 100644
index 5555dcf841a..00000000000
--- a/.github/workflows/publish-benchmarks-website.yml
+++ /dev/null
@@ -1,38 +0,0 @@
-name: Publish Benchmarks Website
-
-on:
- push:
- branches: [develop]
- paths:
- - "benchmarks-website/**"
-
-jobs:
- publish:
- runs-on: ubuntu-latest
- timeout-minutes: 10
- permissions:
- contents: read
- packages: write
- steps:
- - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
-
- - name: Log in to GHCR
- uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4
- with:
- registry: ghcr.io
- username: ${{ github.actor }}
- password: ${{ secrets.GITHUB_TOKEN }}
-
- - name: Set up QEMU
- uses: docker/setup-qemu-action@06116385d9baf250c9f4dcb4858b16962ea869c3 # v4
-
- - name: Set up Docker Buildx
- uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4
-
- - name: Build and push
- uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7
- with:
- context: ./benchmarks-website
- platforms: linux/arm64
- push: true
- tags: ghcr.io/${{ github.repository }}/benchmarks-website:latest
diff --git a/REUSE.toml b/REUSE.toml
index fb3079a046d..6ce32411711 100644
--- a/REUSE.toml
+++ b/REUSE.toml
@@ -12,11 +12,6 @@ path = "vortex-btrblocks/decision-tree.*"
SPDX-FileCopyrightText = "Copyright the Vortex contributors"
SPDX-License-Identifier = "CC-BY-4.0"
-[[annotations]]
-path = "benchmarks-website/**"
-SPDX-FileCopyrightText = "Copyright the Vortex contributors"
-SPDX-License-Identifier = "CC-BY-4.0"
-
# Golden files are licensed under CC-BY-4.0.
[[annotations]]
path = "**/goldenfiles/**"
diff --git a/_typos.toml b/_typos.toml
index d5d2a8e4db3..359b89c80fb 100644
--- a/_typos.toml
+++ b/_typos.toml
@@ -11,7 +11,7 @@ extend-ignore-re = [
# scripts/measurement_id_golden.json is a frozen hash-pin artifact whose vectors include
# deliberate Unicode edge cases (JSON-escaped, so "café" reads as the token "caf"); its bytes
# must never change, so it is excluded rather than "fixed".
-extend-exclude = ["/vortex-bench/**", "/docs/references.bib", "benchmarks/**", "vortex-sqllogictest/slt/**", "encodings/fsst/src/dfa/tests.rs", "encodings/fsst/src/dfa/flat_contains.rs", "benchmarks-website/server/static/**", "benchmarks-website/server/tests/snapshots/**", "scripts/measurement_id_golden.json"]
+extend-exclude = ["/vortex-bench/**", "/docs/references.bib", "benchmarks/**", "vortex-sqllogictest/slt/**", "encodings/fsst/src/dfa/tests.rs", "encodings/fsst/src/dfa/flat_contains.rs", "scripts/measurement_id_golden.json"]
[type.py]
extend-ignore-identifiers-re = [
diff --git a/benchmarks-website/.dockerignore b/benchmarks-website/.dockerignore
deleted file mode 100644
index a21f178d3ab..00000000000
--- a/benchmarks-website/.dockerignore
+++ /dev/null
@@ -1,3 +0,0 @@
-node_modules
-dist
-.git
diff --git a/benchmarks-website/.gitignore b/benchmarks-website/.gitignore
deleted file mode 100644
index 76add878f8d..00000000000
--- a/benchmarks-website/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-node_modules
-dist
\ No newline at end of file
diff --git a/benchmarks-website/Dockerfile b/benchmarks-website/Dockerfile
deleted file mode 100644
index 1f87a7148b5..00000000000
--- a/benchmarks-website/Dockerfile
+++ /dev/null
@@ -1,16 +0,0 @@
-FROM node:24-alpine AS build
-WORKDIR /app
-COPY package.json package-lock.json ./
-RUN npm ci
-COPY . .
-RUN npm run build
-
-FROM node:24-alpine
-WORKDIR /app
-COPY package.json package-lock.json ./
-RUN npm ci --omit=dev
-COPY --from=build /app/dist ./dist
-COPY server.js .
-COPY src/config.js ./src/config.js
-EXPOSE 3000
-CMD ["node", "server.js"]
diff --git a/benchmarks-website/README.md b/benchmarks-website/README.md
deleted file mode 100644
index 01bbcc265fd..00000000000
--- a/benchmarks-website/README.md
+++ /dev/null
@@ -1,119 +0,0 @@
-
-
-# bench.vortex.dev
-
-The website behind `bench.vortex.dev`. The directory currently houses **two
-implementations side by side**, run together until the v3 cutover lands:
-
-- **v2** (top-level files: `server.js`, `src/`, `index.html`, `vite.config.js`,
- `package.json`, `Dockerfile`, `docker-compose.yml`, `public/`). The Node +
- React stack that has shipped to production for the life of the site. Built
- and published by
- [`.github/workflows/publish-benchmarks-website.yml`](../.github/workflows/publish-benchmarks-website.yml).
-- **v3** (`server/` + `migrate/` + `ops/`). A single Rust binary -
- [`vortex-bench-server`](server/) - that owns a DuckDB file on local disk,
- serves the API, and renders the HTML. Compiles all static assets
- (`chart.umd.js`, `chart-init.js`, `style.css`) into the binary so deploys
- are one file plus a database. Built directly on the EC2 host by
- [`ops/deploy.sh`](ops/deploy.sh) - see [`ops/README.md`](ops/README.md).
- [`migrate/`](migrate/) is a one-shot tool that loads v2's S3 dataset into a
- v3 DuckDB; it is throwaway and goes away after cutover.
-
-Live results are produced by
-[`.github/workflows/bench.yml`](../.github/workflows/bench.yml) and
-[`.github/workflows/sql-benchmarks.yml`](../.github/workflows/sql-benchmarks.yml),
-which CI runs after every push to `develop`. Until cutover the same payload is
-emitted to both stacks (v2 via the legacy `--gh-json` path appended to a public
-S3 bucket; v3 via `--gh-json-v3` POSTed to `/api/ingest`).
-
-## v3 architecture in one paragraph
-
-`axum` (HTTP) + `maud` (compile-time HTML) + embedded `duckdb-rs` over a single
-local DB file. Five fact tables (`query_measurements`, `compression_times`,
-`compression_sizes`, `random_access_times`, `vector_search_runs`) plus a
-`commits` dim table - see [`server/src/schema.rs`](server/src/schema.rs) for
-the column contracts. Three HTML routes (`/`, `/chart/{slug}`,
-`/group/{slug}`) and four stable JSON routes (`GET /api/groups`,
-`GET /api/chart/{slug}`, `GET /api/group/{slug}`, `GET /health`), plus
-versioned group shard artifacts and bearer-gated `POST /api/ingest`. The hot
-website path serves precomputed, precompressed latest-100 artifacts from an
-in-memory read model; pages render chart shells and hydrate groups via shard
-artifacts, while full history warms in the background. See
-[`server/ARCHITECTURE.md`](server/ARCHITECTURE.md).
-
-For the per-module crate map and the request-flow walkthrough, see the
-`//!` doc on [`server/src/lib.rs`](server/src/lib.rs). The producer side of
-the ingest contract lives in
-[`vortex-bench/src/v3.rs`](../vortex-bench/src/v3.rs); the historical-data
-side in [`migrate/src/classifier.rs`](migrate/src/classifier.rs).
-
-## Local dev
-
-```bash
-# v3 server (DuckDB lives at ./bench.duckdb by default).
-INGEST_BEARER_TOKEN=dev cargo run -p vortex-bench-server
-# server logs: "bench server listening addr=127.0.0.1:3000 db=bench.duckdb"
-
-# v3 historical migrator (writes a fully populated DuckDB the server can open).
-cargo run -p vortex-bench-migrate -- run --output ./bench.duckdb
-```
-
-Ingest fixture data via the snapshot tests' envelopes (see
-[`server/tests/common/mod.rs`](server/tests/common/mod.rs)) or by hand-rolling
-a JSONL file and POSTing through `scripts/post-ingest.py`.
-
-```bash
-cargo nextest run -p vortex-bench-server -p vortex-bench-migrate
-INSTA_UPDATE=auto cargo nextest run -p vortex-bench-server # update snapshots
-```
-
-For the v2 stack:
-
-```bash
-cd benchmarks-website
-npm install
-npm run dev
-```
-
-## Deployment
-
-v3 runs as a systemd service on a single EC2 host. The full operator
-runbook (first-time install, day-to-day, failure modes) is in
-[`ops/README.md`](ops/README.md). Summary:
-
-- A `vortex-bench-deploy.timer` polls `origin/develop` every 60s. If commits
- in the range touch `benchmarks-website/server/`, `benchmarks-website/migrate/`,
- `Cargo.toml`, or `Cargo.lock`, it builds and atomically swaps the binary,
- then verifies `/health`. Otherwise it fast-forwards the working tree and
- exits silently.
-- A `vortex-bench-backup.timer` fires hourly: it asks the server to write a
- per-table Vortex snapshot (`schema.sql` plus one `
.vortex` file per
- table) via the bearer-gated `/api/admin/snapshot` endpoint, `tar czf`s the
- snapshot directory into `.tar.gz`, uploads it to
- `s3://vortex-benchmark-results-database/v3-backups/`, and deletes the local
- copies.
-- For ad-hoc reads against the live DB, `ops/inspect.sh` calls a
- bearer-gated `/api/admin/sql` endpoint - no server stop required.
-
-The v3 server is throwaway-friendly: every request runs against the local
-DuckDB file, and a fresh boot reapplies the schema DDL idempotently. The
-migrator deletes the target file (and its `.wal`) before populating it, so
-re-running `vortex-bench-migrate run --output ...` is safe.
-
-## Cutover plan (in flight)
-
-The work to flip `bench.vortex.dev` from v2 to v3 is tracked outside this
-repo. The relevant code-side bits:
-
-- v3 runs alongside v2 on the same EC2 host today and is fed by CI's
- dual-write `--gh-json-v3` path.
-- v2 keeps shipping unchanged until DNS flips. **Do not touch the top-level
- v2 files unless you are doing the cleanup PR opened post-flip.**
-- The v2 cleanup PR removes everything top-level under `benchmarks-website/`
- that belongs to v2 (`server.js`, `src/`, `index.html`, `vite.config.js`,
- `package.json`, `package-lock.json`, `public/`, the top-level `Dockerfile`,
- `docker-compose.yml`, and the `publish-benchmarks-website.yml` workflow).
- The v3 tree under `server/`, `migrate/`, and `ops/` is untouched.
diff --git a/benchmarks-website/docker-compose.yml b/benchmarks-website/docker-compose.yml
deleted file mode 100644
index b97482a230a..00000000000
--- a/benchmarks-website/docker-compose.yml
+++ /dev/null
@@ -1,29 +0,0 @@
-services:
- benchmarks-website:
- image: ghcr.io/vortex-data/vortex/benchmarks-website:latest
- ports:
- - "80:3000"
- restart: unless-stopped
-
- vortex-bench-server:
- image: ghcr.io/vortex-data/vortex/vortex-bench-server:latest
- ports:
- - "3001:3000"
- environment:
- VORTEX_BENCH_DB: "/app/data/bench.duckdb"
- VORTEX_BENCH_BIND: "0.0.0.0:3000"
- VORTEX_BENCH_LOG: "info,vortex_bench_server=debug"
- env_file:
- - /etc/vortex-bench/secrets.env
- volumes:
- - /opt/benchmarks-website/data:/app/data
- restart: unless-stopped
-
- watchtower:
- image: containrrr/watchtower
- volumes:
- - /var/run/docker.sock:/var/run/docker.sock
- environment:
- - WATCHTOWER_POLL_INTERVAL=60
- - WATCHTOWER_CLEANUP=true
- restart: unless-stopped
diff --git a/benchmarks-website/index.html b/benchmarks-website/index.html
deleted file mode 100644
index e475f3ad254..00000000000
--- a/benchmarks-website/index.html
+++ /dev/null
@@ -1,36 +0,0 @@
-
-
-
-
-
- Vortex Benchmarks
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/benchmarks-website/package-lock.json b/benchmarks-website/package-lock.json
deleted file mode 100644
index 7eb09dbfa84..00000000000
--- a/benchmarks-website/package-lock.json
+++ /dev/null
@@ -1,1324 +0,0 @@
-{
- "name": "vortex-benchmarks-website",
- "version": "2.0.0",
- "lockfileVersion": 3,
- "requires": true,
- "packages": {
- "": {
- "name": "vortex-benchmarks-website",
- "version": "2.0.0",
- "dependencies": {
- "chart.js": "^4.5.1",
- "chartjs-plugin-zoom": "^2.2.0",
- "downsample": "^1.4.0",
- "hammerjs": "^2.0.8",
- "lucide-react": "^1.11.0",
- "react": "^19.2.5",
- "react-chartjs-2": "^5.3.1",
- "react-dom": "^19.2.5"
- },
- "devDependencies": {
- "@types/react": "^19.2.14",
- "@types/react-dom": "^19.2.3",
- "@vitejs/plugin-react": "^6.0.1",
- "concurrently": "^10.0.0",
- "vite": "^8.0.10"
- },
- "engines": {
- "node": ">=18.0.0"
- }
- },
- "node_modules/@emnapi/core": {
- "version": "1.11.1",
- "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz",
- "integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==",
- "dev": true,
- "license": "MIT",
- "optional": true,
- "dependencies": {
- "@emnapi/wasi-threads": "1.2.2",
- "tslib": "^2.4.0"
- }
- },
- "node_modules/@emnapi/runtime": {
- "version": "1.11.1",
- "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.1.tgz",
- "integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==",
- "dev": true,
- "license": "MIT",
- "optional": true,
- "dependencies": {
- "tslib": "^2.4.0"
- }
- },
- "node_modules/@emnapi/wasi-threads": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz",
- "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==",
- "dev": true,
- "license": "MIT",
- "optional": true,
- "dependencies": {
- "tslib": "^2.4.0"
- }
- },
- "node_modules/@kurkle/color": {
- "version": "0.3.4",
- "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.4.tgz",
- "integrity": "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==",
- "license": "MIT"
- },
- "node_modules/@napi-rs/wasm-runtime": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.6.tgz",
- "integrity": "sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==",
- "dev": true,
- "license": "MIT",
- "optional": true,
- "dependencies": {
- "@tybys/wasm-util": "^0.10.3"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/Brooooooklyn"
- },
- "peerDependencies": {
- "@emnapi/core": "^1.7.1",
- "@emnapi/runtime": "^1.7.1"
- }
- },
- "node_modules/@oxc-project/types": {
- "version": "0.138.0",
- "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.138.0.tgz",
- "integrity": "sha512-1a7ZKmrRTCoN1XMZ4L0PyyqrMnrNlLyPuOkdSX2MZg7IiIGRUyurNhAm73ptDOraoBcIordsIGKNPKUzy3ZmfA==",
- "dev": true,
- "license": "MIT",
- "funding": {
- "url": "https://github.com/sponsors/Boshen"
- }
- },
- "node_modules/@rolldown/binding-android-arm64": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.1.4.tgz",
- "integrity": "sha512-EZLpf/8y7GXkkra90ML47kzik/GMP3EMcE9bPyHmRfxLC6z9+aW5A8poCsoxjrT5GfEcNAAvWwUHjvP1pUQkfw==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "android"
- ],
- "engines": {
- "node": "^20.19.0 || >=22.12.0"
- }
- },
- "node_modules/@rolldown/binding-darwin-arm64": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.1.4.tgz",
- "integrity": "sha512-aUi+HBvmYb7j8krl1+qJgkG8C17fO79gk3c+jPw4S8glRFc1DTija9S3EyaTSQUm5GJXYKDAsugBEhFHH2vYiQ==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": "^20.19.0 || >=22.12.0"
- }
- },
- "node_modules/@rolldown/binding-darwin-x64": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.1.4.tgz",
- "integrity": "sha512-F7hHC3gwY11+vByKPRWqwGbeXWVgKmL+pTGCinaEhdihzBV2aQ0fvZOch9cXYUOKuKKq429HeYXOqQLc7wFCEg==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": "^20.19.0 || >=22.12.0"
- }
- },
- "node_modules/@rolldown/binding-freebsd-x64": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.1.4.tgz",
- "integrity": "sha512-sI5yw+7s92SK6odiEhD5lKCBlWcpjHS5qyqpVQbZAJ0fIzEUXrmbl3DH2ybR3PZogulNJF+COLtmA8hUfvkCCQ==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "freebsd"
- ],
- "engines": {
- "node": "^20.19.0 || >=22.12.0"
- }
- },
- "node_modules/@rolldown/binding-linux-arm-gnueabihf": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.1.4.tgz",
- "integrity": "sha512-mCi0OKgEieFircrtVYmQAFGszRtMnZ6fpZAXrxanXAu7lqZcsK1E1RAaZNG0uKAnxox3B1f4EyQNnoyMfN1vAA==",
- "cpu": [
- "arm"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": "^20.19.0 || >=22.12.0"
- }
- },
- "node_modules/@rolldown/binding-linux-arm64-gnu": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.1.4.tgz",
- "integrity": "sha512-B9Ial3Kv5sh0SHnB1g/QWcUQCEvCF6QKGAl4zXypYj65mVI+B4AhFBwPtSN7pDrJeIx8Z7zdy4ntx+wQABom7w==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "libc": [
- "glibc"
- ],
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": "^20.19.0 || >=22.12.0"
- }
- },
- "node_modules/@rolldown/binding-linux-arm64-musl": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.1.4.tgz",
- "integrity": "sha512-lZVym0PuHE1KZ22gmFTC15lAkrg9iTszR617oYRB/iPY1A56ywoJzVKOJBKaot5RiikCObmur6pogpse3gRcng==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "libc": [
- "musl"
- ],
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": "^20.19.0 || >=22.12.0"
- }
- },
- "node_modules/@rolldown/binding-linux-ppc64-gnu": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.1.4.tgz",
- "integrity": "sha512-t2DNiLJWNTbnEHyUzTumldML6ET4/g16467LZoDDJ3tSxGvguL5/NyC2lCsNKuyRycg9XeDQF5SSv+TNOhQEXg==",
- "cpu": [
- "ppc64"
- ],
- "dev": true,
- "libc": [
- "glibc"
- ],
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": "^20.19.0 || >=22.12.0"
- }
- },
- "node_modules/@rolldown/binding-linux-s390x-gnu": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.1.4.tgz",
- "integrity": "sha512-0WIRnL1Uw4BvTZRLQt+PVgo6ZKTJadlC2btP+/EOXv2f/DWbY0rEgl+y834mIVwP1FkTlWVTrGGJXf12lru7EQ==",
- "cpu": [
- "s390x"
- ],
- "dev": true,
- "libc": [
- "glibc"
- ],
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": "^20.19.0 || >=22.12.0"
- }
- },
- "node_modules/@rolldown/binding-linux-x64-gnu": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.1.4.tgz",
- "integrity": "sha512-JWtGshGfX+oENAKonoNkqEJX+7hC8yfhi9GUyPX1VX4mdh1y5r+ZiJLR5XzAB0aoP6s/PcILsGjKq8O0mm24bw==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "libc": [
- "glibc"
- ],
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": "^20.19.0 || >=22.12.0"
- }
- },
- "node_modules/@rolldown/binding-linux-x64-musl": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.1.4.tgz",
- "integrity": "sha512-rT6yQcxUuXs4CnbofqwHRRV0iem349rLMYpTjkgQGLjrY4ado/eDzwPZPTCgTOlF6Nkp8NEv70yLMTn6qkWxsQ==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "libc": [
- "musl"
- ],
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": "^20.19.0 || >=22.12.0"
- }
- },
- "node_modules/@rolldown/binding-openharmony-arm64": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.1.4.tgz",
- "integrity": "sha512-KXMGoboq5cyaCQjDA4GLuRiOwBQ0EyFnJoVViLeZ45/3rFItRODEr+NdsBcVpll40hhNArlm/speWGRvj08LzA==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "openharmony"
- ],
- "engines": {
- "node": "^20.19.0 || >=22.12.0"
- }
- },
- "node_modules/@rolldown/binding-wasm32-wasi": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.1.4.tgz",
- "integrity": "sha512-5K83rb36oJiY7BCyE9zLZtGcPV4g5wvq+xwdO0XPIwDVZI8cyB/AUjkNXGb92/rnmezEkjMOpgY61rtwjQtFwg==",
- "cpu": [
- "wasm32"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "dependencies": {
- "@emnapi/core": "1.11.1",
- "@emnapi/runtime": "1.11.1",
- "@napi-rs/wasm-runtime": "^1.1.6"
- },
- "engines": {
- "node": "^20.19.0 || >=22.12.0"
- }
- },
- "node_modules/@rolldown/binding-win32-arm64-msvc": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.1.4.tgz",
- "integrity": "sha512-PnWBtw3TV5KOg69HQQDR0mnQuyCmSGR2pAB4DC1rPF808fgKeTUMj2EOEyKATpgiuxuR5APQmiDO7PDgEjTFSA==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": "^20.19.0 || >=22.12.0"
- }
- },
- "node_modules/@rolldown/binding-win32-x64-msvc": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.1.4.tgz",
- "integrity": "sha512-M1lpniBePobTfsa7Ks9a199e1akxsXn+GYBUKsEzv3YFzOm1HJAMNwKI3qr0Zq+mxwx9gOZoTdP1yXRYsZUocQ==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": "^20.19.0 || >=22.12.0"
- }
- },
- "node_modules/@rolldown/pluginutils": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz",
- "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/@tybys/wasm-util": {
- "version": "0.10.3",
- "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz",
- "integrity": "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==",
- "dev": true,
- "license": "MIT",
- "optional": true,
- "dependencies": {
- "tslib": "^2.4.0"
- }
- },
- "node_modules/@types/hammerjs": {
- "version": "2.0.46",
- "resolved": "https://registry.npmjs.org/@types/hammerjs/-/hammerjs-2.0.46.tgz",
- "integrity": "sha512-ynRvcq6wvqexJ9brDMS4BnBLzmr0e14d6ZJTEShTBWKymQiHwlAyGu0ZPEFI2Fh1U53F7tN9ufClWM5KvqkKOw==",
- "license": "MIT"
- },
- "node_modules/@types/react": {
- "version": "19.2.17",
- "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz",
- "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "csstype": "^3.2.2"
- }
- },
- "node_modules/@types/react-dom": {
- "version": "19.2.3",
- "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz",
- "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
- "dev": true,
- "license": "MIT",
- "peerDependencies": {
- "@types/react": "^19.2.0"
- }
- },
- "node_modules/@vitejs/plugin-react": {
- "version": "6.0.3",
- "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.3.tgz",
- "integrity": "sha512-vmFvco5/QuC2f9Oj+wTk0+9XeDFkHxSamwZKYc7MxYwKICfvUvlMhqKI0VuICPltGqh1neqBKDvO4kes1ya8vg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@rolldown/pluginutils": "^1.0.1"
- },
- "engines": {
- "node": "^20.19.0 || >=22.12.0"
- },
- "peerDependencies": {
- "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0",
- "babel-plugin-react-compiler": "^1.0.0",
- "vite": "^8.0.0"
- },
- "peerDependenciesMeta": {
- "@rolldown/plugin-babel": {
- "optional": true
- },
- "babel-plugin-react-compiler": {
- "optional": true
- }
- }
- },
- "node_modules/ansi-regex": {
- "version": "6.2.2",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz",
- "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-regex?sponsor=1"
- }
- },
- "node_modules/ansi-styles": {
- "version": "6.2.3",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz",
- "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/chalk": {
- "version": "5.6.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz",
- "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": "^12.17.0 || ^14.13 || >=16.0.0"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/chart.js": {
- "version": "4.5.1",
- "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.5.1.tgz",
- "integrity": "sha512-GIjfiT9dbmHRiYi6Nl2yFCq7kkwdkp1W/lp2J99rX0yo9tgJGn3lKQATztIjb5tVtevcBtIdICNWqlq5+E8/Pw==",
- "license": "MIT",
- "dependencies": {
- "@kurkle/color": "^0.3.0"
- },
- "engines": {
- "pnpm": ">=8"
- }
- },
- "node_modules/chartjs-plugin-zoom": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/chartjs-plugin-zoom/-/chartjs-plugin-zoom-2.2.0.tgz",
- "integrity": "sha512-in6kcdiTlP6npIVLMd4zXZ08PDUXC52gZ4FAy5oyjk1zX3gKarXMAof7B9eFiisf9WOC3bh2saHg+J5WtLXZeA==",
- "license": "MIT",
- "dependencies": {
- "@types/hammerjs": "^2.0.45",
- "hammerjs": "^2.0.8"
- },
- "peerDependencies": {
- "chart.js": ">=3.2.0"
- }
- },
- "node_modules/cliui": {
- "version": "9.0.1",
- "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz",
- "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "string-width": "^7.2.0",
- "strip-ansi": "^7.1.0",
- "wrap-ansi": "^9.0.0"
- },
- "engines": {
- "node": ">=20"
- }
- },
- "node_modules/concurrently": {
- "version": "10.0.3",
- "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-10.0.3.tgz",
- "integrity": "sha512-hc3LH4UaKWd/bbyDK/IGVa4RB6PtQ3CUYwtrkzqHn+wIG3Hr5fhpRlk0L/gCa8ZE1L/Ufj50Zho69cI5w8SQBA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "chalk": "5.6.2",
- "rxjs": "7.8.2",
- "shell-quote": "1.8.4",
- "supports-color": "10.2.2",
- "tree-kill": "1.2.2",
- "yargs": "18.0.0"
- },
- "bin": {
- "conc": "dist/bin/index.js",
- "concurrently": "dist/bin/index.js"
- },
- "engines": {
- "node": ">=22"
- },
- "funding": {
- "url": "https://github.com/open-cli-tools/concurrently?sponsor=1"
- }
- },
- "node_modules/csstype": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
- "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/detect-libc": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
- "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
- "dev": true,
- "license": "Apache-2.0",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/downsample": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/downsample/-/downsample-1.4.0.tgz",
- "integrity": "sha512-teYPhUPxqwtyICt47t1mP/LjhbRV/ghuKb/LmFDbcZ0CjqFD31tn6rVLZoeCEa1xr8+f2skW8UjRiLiGIKQE4w==",
- "license": "MIT"
- },
- "node_modules/emoji-regex": {
- "version": "10.6.0",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz",
- "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/escalade": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
- "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/fdir": {
- "version": "6.5.0",
- "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
- "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=12.0.0"
- },
- "peerDependencies": {
- "picomatch": "^3 || ^4"
- },
- "peerDependenciesMeta": {
- "picomatch": {
- "optional": true
- }
- }
- },
- "node_modules/fsevents": {
- "version": "2.3.3",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
- "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
- "dev": true,
- "hasInstallScript": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
- }
- },
- "node_modules/get-caller-file": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
- "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
- "dev": true,
- "license": "ISC",
- "engines": {
- "node": "6.* || 8.* || >= 10.*"
- }
- },
- "node_modules/get-east-asian-width": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz",
- "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/hammerjs": {
- "version": "2.0.8",
- "resolved": "https://registry.npmjs.org/hammerjs/-/hammerjs-2.0.8.tgz",
- "integrity": "sha512-tSQXBXS/MWQOn/RKckawJ61vvsDpCom87JgxiYdGwHdOa0ht0vzUWDlfioofFCRU0L+6NGDt6XzbgoJvZkMeRQ==",
- "license": "MIT",
- "engines": {
- "node": ">=0.8.0"
- }
- },
- "node_modules/lightningcss": {
- "version": "1.32.0",
- "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz",
- "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==",
- "dev": true,
- "license": "MPL-2.0",
- "dependencies": {
- "detect-libc": "^2.0.3"
- },
- "engines": {
- "node": ">= 12.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/parcel"
- },
- "optionalDependencies": {
- "lightningcss-android-arm64": "1.32.0",
- "lightningcss-darwin-arm64": "1.32.0",
- "lightningcss-darwin-x64": "1.32.0",
- "lightningcss-freebsd-x64": "1.32.0",
- "lightningcss-linux-arm-gnueabihf": "1.32.0",
- "lightningcss-linux-arm64-gnu": "1.32.0",
- "lightningcss-linux-arm64-musl": "1.32.0",
- "lightningcss-linux-x64-gnu": "1.32.0",
- "lightningcss-linux-x64-musl": "1.32.0",
- "lightningcss-win32-arm64-msvc": "1.32.0",
- "lightningcss-win32-x64-msvc": "1.32.0"
- }
- },
- "node_modules/lightningcss-android-arm64": {
- "version": "1.32.0",
- "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz",
- "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MPL-2.0",
- "optional": true,
- "os": [
- "android"
- ],
- "engines": {
- "node": ">= 12.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/parcel"
- }
- },
- "node_modules/lightningcss-darwin-arm64": {
- "version": "1.32.0",
- "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz",
- "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MPL-2.0",
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": ">= 12.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/parcel"
- }
- },
- "node_modules/lightningcss-darwin-x64": {
- "version": "1.32.0",
- "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz",
- "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MPL-2.0",
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": ">= 12.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/parcel"
- }
- },
- "node_modules/lightningcss-freebsd-x64": {
- "version": "1.32.0",
- "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz",
- "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MPL-2.0",
- "optional": true,
- "os": [
- "freebsd"
- ],
- "engines": {
- "node": ">= 12.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/parcel"
- }
- },
- "node_modules/lightningcss-linux-arm-gnueabihf": {
- "version": "1.32.0",
- "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz",
- "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==",
- "cpu": [
- "arm"
- ],
- "dev": true,
- "license": "MPL-2.0",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">= 12.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/parcel"
- }
- },
- "node_modules/lightningcss-linux-arm64-gnu": {
- "version": "1.32.0",
- "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz",
- "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "libc": [
- "glibc"
- ],
- "license": "MPL-2.0",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">= 12.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/parcel"
- }
- },
- "node_modules/lightningcss-linux-arm64-musl": {
- "version": "1.32.0",
- "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz",
- "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "libc": [
- "musl"
- ],
- "license": "MPL-2.0",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">= 12.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/parcel"
- }
- },
- "node_modules/lightningcss-linux-x64-gnu": {
- "version": "1.32.0",
- "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz",
- "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "libc": [
- "glibc"
- ],
- "license": "MPL-2.0",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">= 12.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/parcel"
- }
- },
- "node_modules/lightningcss-linux-x64-musl": {
- "version": "1.32.0",
- "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz",
- "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "libc": [
- "musl"
- ],
- "license": "MPL-2.0",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">= 12.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/parcel"
- }
- },
- "node_modules/lightningcss-win32-arm64-msvc": {
- "version": "1.32.0",
- "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz",
- "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MPL-2.0",
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">= 12.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/parcel"
- }
- },
- "node_modules/lightningcss-win32-x64-msvc": {
- "version": "1.32.0",
- "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz",
- "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MPL-2.0",
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">= 12.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/parcel"
- }
- },
- "node_modules/lucide-react": {
- "version": "1.23.0",
- "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.23.0.tgz",
- "integrity": "sha512-38BpJcD0JhFosxHApP/BYsBetLpQFRoTRzEzstM/XCc3jsAG7wqaY1lgVwxiUe3xqYE+lNxo2PkCmYwXWrwwIw==",
- "license": "ISC",
- "peerDependencies": {
- "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
- }
- },
- "node_modules/nanoid": {
- "version": "3.3.15",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.15.tgz",
- "integrity": "sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/ai"
- }
- ],
- "license": "MIT",
- "bin": {
- "nanoid": "bin/nanoid.cjs"
- },
- "engines": {
- "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
- }
- },
- "node_modules/picocolors": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
- "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
- "dev": true,
- "license": "ISC"
- },
- "node_modules/picomatch": {
- "version": "4.0.5",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz",
- "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/jonschlinkert"
- }
- },
- "node_modules/postcss": {
- "version": "8.5.16",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.16.tgz",
- "integrity": "sha512-vuwillviilfKZsg0VGj5R/YwwcHx4SLsIOI/7K6mQkWx+l5cUHTjj5g0AasTBcyXsbfTgrwsUNmVUb5xVwyPwg==",
- "dev": true,
- "funding": [
- {
- "type": "opencollective",
- "url": "https://opencollective.com/postcss/"
- },
- {
- "type": "tidelift",
- "url": "https://tidelift.com/funding/github/npm/postcss"
- },
- {
- "type": "github",
- "url": "https://github.com/sponsors/ai"
- }
- ],
- "license": "MIT",
- "dependencies": {
- "nanoid": "^3.3.12",
- "picocolors": "^1.1.1",
- "source-map-js": "^1.2.1"
- },
- "engines": {
- "node": "^10 || ^12 || >=14"
- }
- },
- "node_modules/react": {
- "version": "19.2.7",
- "resolved": "https://registry.npmjs.org/react/-/react-19.2.7.tgz",
- "integrity": "sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==",
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/react-chartjs-2": {
- "version": "5.3.1",
- "resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-5.3.1.tgz",
- "integrity": "sha512-h5IPXKg9EXpjoBzUfyWJvllMjG2mQ4EiuHQFhms/AjUm0XSZHhyRy2xVmLXHKrtcdrPO4mnGqRtYoD0vp95A0A==",
- "license": "MIT",
- "peerDependencies": {
- "chart.js": "^4.1.1",
- "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
- }
- },
- "node_modules/react-dom": {
- "version": "19.2.7",
- "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.7.tgz",
- "integrity": "sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==",
- "license": "MIT",
- "dependencies": {
- "scheduler": "^0.27.0"
- },
- "peerDependencies": {
- "react": "^19.2.7"
- }
- },
- "node_modules/rolldown": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.1.4.tgz",
- "integrity": "sha512-IjZYiLxZwpnhwhdBH2ugdTGVSdhCQUmLxLoqyjiL0JxYjyRst+5a0P3xfrTxJ5F638j4Mvvw5FAX5XE6eHpXbA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@oxc-project/types": "=0.138.0",
- "@rolldown/pluginutils": "^1.0.0"
- },
- "bin": {
- "rolldown": "bin/cli.mjs"
- },
- "engines": {
- "node": "^20.19.0 || >=22.12.0"
- },
- "optionalDependencies": {
- "@rolldown/binding-android-arm64": "1.1.4",
- "@rolldown/binding-darwin-arm64": "1.1.4",
- "@rolldown/binding-darwin-x64": "1.1.4",
- "@rolldown/binding-freebsd-x64": "1.1.4",
- "@rolldown/binding-linux-arm-gnueabihf": "1.1.4",
- "@rolldown/binding-linux-arm64-gnu": "1.1.4",
- "@rolldown/binding-linux-arm64-musl": "1.1.4",
- "@rolldown/binding-linux-ppc64-gnu": "1.1.4",
- "@rolldown/binding-linux-s390x-gnu": "1.1.4",
- "@rolldown/binding-linux-x64-gnu": "1.1.4",
- "@rolldown/binding-linux-x64-musl": "1.1.4",
- "@rolldown/binding-openharmony-arm64": "1.1.4",
- "@rolldown/binding-wasm32-wasi": "1.1.4",
- "@rolldown/binding-win32-arm64-msvc": "1.1.4",
- "@rolldown/binding-win32-x64-msvc": "1.1.4"
- }
- },
- "node_modules/rxjs": {
- "version": "7.8.2",
- "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
- "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==",
- "dev": true,
- "license": "Apache-2.0",
- "dependencies": {
- "tslib": "^2.1.0"
- }
- },
- "node_modules/scheduler": {
- "version": "0.27.0",
- "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz",
- "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==",
- "license": "MIT"
- },
- "node_modules/shell-quote": {
- "version": "1.8.4",
- "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.4.tgz",
- "integrity": "sha512-VsC6n6vz1ihYYyZZwX7YZSF5l5x36ca17OC+a69h94YqB7X6XLwf+5MOgynYir2SLFUbl8gIYvBo8K8RoNQ6bQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/source-map-js": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
- "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
- "dev": true,
- "license": "BSD-3-Clause",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/string-width": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz",
- "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "emoji-regex": "^10.3.0",
- "get-east-asian-width": "^1.0.0",
- "strip-ansi": "^7.1.0"
- },
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/strip-ansi": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz",
- "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "ansi-regex": "^6.2.2"
- },
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/chalk/strip-ansi?sponsor=1"
- }
- },
- "node_modules/supports-color": {
- "version": "10.2.2",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-10.2.2.tgz",
- "integrity": "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "url": "https://github.com/chalk/supports-color?sponsor=1"
- }
- },
- "node_modules/tinyglobby": {
- "version": "0.2.17",
- "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz",
- "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "fdir": "^6.5.0",
- "picomatch": "^4.0.4"
- },
- "engines": {
- "node": ">=12.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/SuperchupuDev"
- }
- },
- "node_modules/tree-kill": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz",
- "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==",
- "dev": true,
- "license": "MIT",
- "bin": {
- "tree-kill": "cli.js"
- }
- },
- "node_modules/tslib": {
- "version": "2.8.1",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
- "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
- "dev": true,
- "license": "0BSD"
- },
- "node_modules/vite": {
- "version": "8.1.3",
- "resolved": "https://registry.npmjs.org/vite/-/vite-8.1.3.tgz",
- "integrity": "sha512-Ds+gBRbj0lwRO2Y5hwnUBdxSwlAve9LeRyU4sNnAr0ewW0gWF0n5bgXgUzbgZ49MV9BVUAQUFYVcDUcilUExMA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "lightningcss": "^1.32.0",
- "picomatch": "^4.0.4",
- "postcss": "^8.5.16",
- "rolldown": "~1.1.3",
- "tinyglobby": "^0.2.17"
- },
- "bin": {
- "vite": "bin/vite.js"
- },
- "engines": {
- "node": "^20.19.0 || >=22.12.0"
- },
- "funding": {
- "url": "https://github.com/vitejs/vite?sponsor=1"
- },
- "optionalDependencies": {
- "fsevents": "~2.3.3"
- },
- "peerDependencies": {
- "@types/node": "^20.19.0 || >=22.12.0",
- "@vitejs/devtools": "^0.3.0",
- "esbuild": "^0.27.0 || ^0.28.0",
- "jiti": ">=1.21.0",
- "less": "^4.0.0",
- "sass": "^1.70.0",
- "sass-embedded": "^1.70.0",
- "stylus": ">=0.54.8",
- "sugarss": "^5.0.0",
- "terser": "^5.16.0",
- "tsx": "^4.8.1",
- "yaml": "^2.4.2"
- },
- "peerDependenciesMeta": {
- "@types/node": {
- "optional": true
- },
- "@vitejs/devtools": {
- "optional": true
- },
- "esbuild": {
- "optional": true
- },
- "jiti": {
- "optional": true
- },
- "less": {
- "optional": true
- },
- "sass": {
- "optional": true
- },
- "sass-embedded": {
- "optional": true
- },
- "stylus": {
- "optional": true
- },
- "sugarss": {
- "optional": true
- },
- "terser": {
- "optional": true
- },
- "tsx": {
- "optional": true
- },
- "yaml": {
- "optional": true
- }
- }
- },
- "node_modules/wrap-ansi": {
- "version": "9.0.2",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz",
- "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "ansi-styles": "^6.2.1",
- "string-width": "^7.0.0",
- "strip-ansi": "^7.1.0"
- },
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
- }
- },
- "node_modules/y18n": {
- "version": "5.0.8",
- "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
- "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
- "dev": true,
- "license": "ISC",
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/yargs": {
- "version": "18.0.0",
- "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz",
- "integrity": "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "cliui": "^9.0.1",
- "escalade": "^3.1.1",
- "get-caller-file": "^2.0.5",
- "string-width": "^7.2.0",
- "y18n": "^5.0.5",
- "yargs-parser": "^22.0.0"
- },
- "engines": {
- "node": "^20.19.0 || ^22.12.0 || >=23"
- }
- },
- "node_modules/yargs-parser": {
- "version": "22.0.0",
- "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz",
- "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==",
- "dev": true,
- "license": "ISC",
- "engines": {
- "node": "^20.19.0 || ^22.12.0 || >=23"
- }
- }
- }
-}
diff --git a/benchmarks-website/package.json b/benchmarks-website/package.json
deleted file mode 100644
index a795e0fb22c..00000000000
--- a/benchmarks-website/package.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "name": "vortex-benchmarks-website",
- "version": "2.0.0",
- "type": "module",
- "scripts": {
- "dev": "concurrently \"npm run server\" \"npm run vite\"",
- "vite": "vite",
- "server": "node server.js",
- "build": "vite build",
- "preview": "vite preview"
- },
- "engines": {
- "node": ">=18.0.0"
- },
- "dependencies": {
- "chart.js": "^4.5.1",
- "chartjs-plugin-zoom": "^2.2.0",
- "downsample": "^1.4.0",
- "hammerjs": "^2.0.8",
- "lucide-react": "^1.11.0",
- "react": "^19.2.5",
- "react-chartjs-2": "^5.3.1",
- "react-dom": "^19.2.5"
- },
- "devDependencies": {
- "@types/react": "^19.2.14",
- "@types/react-dom": "^19.2.3",
- "@vitejs/plugin-react": "^6.0.1",
- "concurrently": "^10.0.0",
- "vite": "^8.0.10"
- }
-}
diff --git a/benchmarks-website/public/Vortex_Black_NoBG.png b/benchmarks-website/public/Vortex_Black_NoBG.png
deleted file mode 100644
index b4caa0e0287..00000000000
Binary files a/benchmarks-website/public/Vortex_Black_NoBG.png and /dev/null differ
diff --git a/benchmarks-website/public/Vortex_White_NoBG.png b/benchmarks-website/public/Vortex_White_NoBG.png
deleted file mode 100644
index 702d378306b..00000000000
Binary files a/benchmarks-website/public/Vortex_White_NoBG.png and /dev/null differ
diff --git a/benchmarks-website/public/android-chrome-192x192.png b/benchmarks-website/public/android-chrome-192x192.png
deleted file mode 100644
index 1089ab6a060..00000000000
Binary files a/benchmarks-website/public/android-chrome-192x192.png and /dev/null differ
diff --git a/benchmarks-website/public/android-chrome-512x512.png b/benchmarks-website/public/android-chrome-512x512.png
deleted file mode 100644
index 3cfec717ee4..00000000000
Binary files a/benchmarks-website/public/android-chrome-512x512.png and /dev/null differ
diff --git a/benchmarks-website/public/apple-touch-icon.png b/benchmarks-website/public/apple-touch-icon.png
deleted file mode 100644
index 2b34da9ee0c..00000000000
Binary files a/benchmarks-website/public/apple-touch-icon.png and /dev/null differ
diff --git a/benchmarks-website/public/favicon-16x16.png b/benchmarks-website/public/favicon-16x16.png
deleted file mode 100644
index 81dd776858a..00000000000
Binary files a/benchmarks-website/public/favicon-16x16.png and /dev/null differ
diff --git a/benchmarks-website/public/favicon-32x32.png b/benchmarks-website/public/favicon-32x32.png
deleted file mode 100644
index 8d2cb9edabc..00000000000
Binary files a/benchmarks-website/public/favicon-32x32.png and /dev/null differ
diff --git a/benchmarks-website/public/favicon.ico b/benchmarks-website/public/favicon.ico
deleted file mode 100644
index 3d4e2ff9fe0..00000000000
Binary files a/benchmarks-website/public/favicon.ico and /dev/null differ
diff --git a/benchmarks-website/public/site.webmanifest b/benchmarks-website/public/site.webmanifest
deleted file mode 100644
index ba9480d90de..00000000000
--- a/benchmarks-website/public/site.webmanifest
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "name": "Vortex Benchmarks",
- "short_name": "Benchmarks",
- "icons": [
- {
- "src": "/android-chrome-192x192.png",
- "sizes": "192x192",
- "type": "image/png"
- },
- {
- "src": "/android-chrome-512x512.png",
- "sizes": "512x512",
- "type": "image/png"
- }
- ],
- "theme_color": "#ffffff",
- "background_color": "#ffffff",
- "display": "standalone"
-}
diff --git a/benchmarks-website/server.js b/benchmarks-website/server.js
deleted file mode 100644
index d6d3f98eef9..00000000000
--- a/benchmarks-website/server.js
+++ /dev/null
@@ -1,775 +0,0 @@
-import http from "http";
-import fs from "fs";
-import path from "path";
-import { fileURLToPath } from "url";
-import zlib from "zlib";
-import readline from "readline";
-import { Readable } from "stream";
-import { LTTB } from "downsample";
-import { QUERY_SUITES, FAN_OUT_GROUPS, ENGINE_RENAMES } from "./src/config.js";
-
-const __filename = fileURLToPath(import.meta.url);
-const __dirname = path.dirname(__filename);
-
-// Configuration
-const PORT = process.env.PORT || 3000;
-const DATA_URL =
- process.env.DATA_URL ||
- "https://vortex-ci-benchmark-results.s3.amazonaws.com/data.json.gz";
-const COMMITS_URL =
- process.env.COMMITS_URL ||
- "https://vortex-ci-benchmark-results.s3.amazonaws.com/commits.json";
-const REFRESH_INTERVAL = process.env.REFRESH_INTERVAL || 5 * 60 * 1000;
-const MAX_POINTS = 200;
-const USE_LOCAL_DATA = process.env.USE_LOCAL_DATA === "true";
-
-// Benchmark groups: non-query groups + simple suites + fan-out suites
-const GROUPS = [
- "Compression",
- "Compression Size",
- ...QUERY_SUITES.filter((s) => !s.skip && !s.fanOut).map((s) => s.displayName),
- "Random Access",
- ...FAN_OUT_GROUPS,
-];
-
-const MIME = {
- ".html": "text/html",
- ".js": "application/javascript",
- ".css": "text/css",
- ".json": "application/json",
- ".png": "image/png",
- ".jpg": "image/jpeg",
- ".svg": "image/svg+xml",
- ".ico": "image/x-icon",
- ".woff": "font/woff",
- ".woff2": "font/woff2",
- ".webmanifest": "application/manifest+json",
-};
-
-let store = {
- commits: [],
- groups: {},
- metadata: null,
- downsampled: {},
- lastUpdated: null,
-};
-
-// Utilities
-const rename = (s) => ENGINE_RENAMES[s.toLowerCase()] || ENGINE_RENAMES[s] || s;
-const geoMean = (arr) =>
- arr.length
- ? Math.pow(
- arr.reduce((a, v) => a * v, 1),
- 1 / arr.length,
- )
- : null;
-
-// Categorize benchmarks based on name patterns and metadata
-function getGroup(benchmark) {
- const name = benchmark.name;
- const lower = name.toLowerCase();
-
- // Random Access: "random-access/..." or "random access/..."
- if (
- lower.startsWith("random-access/") ||
- lower.startsWith("random access/")
- ) {
- return "Random Access";
- }
-
- // Compression Size: size measurements
- if (
- lower.startsWith("vortex size/") ||
- lower.startsWith("vortex-file-compressed size/") ||
- lower.startsWith("parquet size/") ||
- lower.startsWith("lance size/") ||
- lower.includes(":raw size/") ||
- lower.includes(":parquet-zstd size/") ||
- lower.includes(":lance size/")
- ) {
- return "Compression Size";
- }
-
- // Compression: compress/decompress time and ratio measurements
- if (
- lower.startsWith("compress time/") ||
- lower.startsWith("decompress time/") ||
- lower.startsWith("parquet_rs-zstd compress") ||
- lower.startsWith("parquet_rs-zstd decompress") ||
- lower.startsWith("lance compress") ||
- lower.startsWith("lance decompress") ||
- lower.startsWith("vortex:lance ratio") ||
- lower.startsWith("vortex:parquet-zstd ratio") ||
- lower.startsWith("vortex:raw ratio")
- ) {
- return "Compression";
- }
-
- // SQL query suites: match "{prefix}_q..." or "{prefix}/..."
- for (const suite of QUERY_SUITES) {
- if (
- !lower.startsWith(suite.prefix + "_q") &&
- !lower.startsWith(suite.prefix + "/")
- )
- continue;
- if (suite.skip) return null;
- if (!suite.fanOut) return suite.displayName;
- // Fan-out suites: expand by storage and scale factor
- const storage = benchmark.storage?.toUpperCase() === "S3" ? "S3" : "NVMe";
- const rawSf = benchmark.dataset?.[suite.datasetKey]?.scale_factor;
- const sf = rawSf ? Math.round(parseFloat(rawSf)) : 1;
- return `${suite.displayName} (${storage}) (SF=${sf})`;
- }
-
- return null;
-}
-
-// Format query name for display: "{prefix}_q00" -> "{QUERY_PREFIX} Q0"
-function formatQuery(q) {
- const lower = q.toLowerCase();
- for (const suite of QUERY_SUITES) {
- if (suite.skip) continue;
- const m = lower.match(new RegExp(`^${suite.prefix}[_ ]?q(\\d+)`, "i"));
- if (m) return `${suite.queryPrefix} Q${parseInt(m[1], 10)}`;
- }
- return q.toUpperCase().replace(/[_-]/g, " ");
-}
-
-function normalizeChartName(group, chartName) {
- if (group === "Compression Size" && chartName === "VORTEX FILE COMPRESSED SIZE") {
- return "VORTEX SIZE";
- }
- return chartName;
-}
-
-// LTTB downsampling
-function lttbIndices(seriesMap, target) {
- const keys = [...seriesMap.keys()];
- if (!keys.length) return [];
- const len = seriesMap.get(keys[0])?.length || 0;
- if (len <= target) return [...Array(len).keys()];
-
- const avg = Array(len);
- for (let i = 0; i < len; i++) {
- let sum = 0,
- n = 0;
- for (const arr of seriesMap.values()) {
- const v = arr[i]?.value ?? arr[i];
- if (v != null && !isNaN(v)) {
- sum += v;
- n++;
- }
- }
- avg[i] = [i, n ? sum / n : 0];
- }
-
- const idx = LTTB(avg, target).map((p) => Math.round(p[0]));
- if (!idx.includes(0)) idx.unshift(0);
- if (!idx.includes(len - 1)) idx.push(len - 1);
- return idx.sort((a, b) => a - b);
-}
-
-function downsample(data, factor) {
- const target = Math.ceil(data.commits.length / factor);
- if (target >= data.commits.length) return data;
-
- const idx = lttbIndices(data.series, target);
- const series = new Map();
- for (const [k, v] of data.series)
- series.set(
- k,
- idx.map((i) => v[i]),
- );
-
- return {
- ...data,
- commits: idx.map((i) => data.commits[i]),
- series,
- originalLength: data.commits.length,
- };
-}
-
-// Data fetching — streams response body directly instead of buffering
-async function fetchJsonl(url) {
- const res = await fetch(url);
- if (!res.ok) throw new Error(`Fetch failed: ${url} ${res.status}`);
- return new Promise((resolve, reject) => {
- const results = [];
- const rl = readline.createInterface({
- input: Readable.fromWeb(res.body),
- crlfDelay: Infinity,
- });
- rl.on("line", (l) => {
- if (l.trim())
- try {
- results.push(JSON.parse(l));
- } catch {}
- });
- rl.on("close", () => resolve(results));
- rl.on("error", reject);
- });
-}
-
-function readLocalJsonl(fp) {
- return new Promise((resolve, reject) => {
- const results = [];
- const rl = readline.createInterface({
- input: fs.createReadStream(fp),
- crlfDelay: Infinity,
- });
- rl.on("line", (l) => {
- if (l.trim())
- try {
- results.push(JSON.parse(l));
- } catch {}
- });
- rl.on("close", () => resolve(results));
- rl.on("error", reject);
- });
-}
-
-// Stream benchmark data record-by-record without buffering the entire dataset
-async function forEachBenchmark(callback) {
- let stream;
- if (USE_LOCAL_DATA) {
- stream = fs.createReadStream(path.join(__dirname, "sample/data.json"));
- } else {
- const res = await fetch(DATA_URL);
- if (!res.ok) throw new Error(`Fetch failed: ${DATA_URL} ${res.status}`);
- stream = Readable.fromWeb(res.body).pipe(zlib.createGunzip());
- }
- return new Promise((resolve, reject) => {
- const rl = readline.createInterface({ input: stream, crlfDelay: Infinity });
- rl.on("line", (l) => {
- if (l.trim())
- try {
- callback(JSON.parse(l));
- } catch {}
- });
- rl.on("close", resolve);
- rl.on("error", reject);
- });
-}
-
-// Main data processing
-async function refresh() {
- console.log("Refreshing data...");
- const t0 = Date.now();
-
- try {
- // Load commits first (small dataset, must be fully in memory for indexing)
- const commitsArr = USE_LOCAL_DATA
- ? await readLocalJsonl(path.join(__dirname, "sample/commits.json"))
- : await fetchJsonl(COMMITS_URL);
-
- // Build commit index (O(1) lookup)
- const commitMap = new Map(commitsArr.map((c) => [c.id, c]));
- const commits = commitsArr.sort(
- (a, b) => new Date(a.timestamp) - new Date(b.timestamp),
- );
- const commitIdx = new Map(commits.map((c, i) => [c.id, i]));
-
- const groups = Object.fromEntries(GROUPS.map((g) => [g, new Map()]));
- let missing = 0;
- let benchmarkCount = 0;
- const uncategorized = new Set();
-
- // Stream benchmarks one record at a time to avoid loading all into memory
- await forEachBenchmark((b) => {
- benchmarkCount++;
- const commit = b.commit || commitMap.get(b.commit_id);
- if (!commit) {
- missing++;
- return;
- }
-
- const group = getGroup(b);
- if (!group) {
- uncategorized.add(b.name.split("/")[0]);
- return;
- }
- if (!groups[group]) return;
-
- // Random access names have the form: random-access/{dataset}/{pattern}/{format}
- // Historical random access names: random-access/{format}
- // Other benchmarks use: {query}/{series}
- let seriesName, chartName;
- const parts = b.name.split("/");
- if (group === "Random Access" && parts.length === 4) {
- chartName = `${parts[1]}/${parts[2]}`.toUpperCase().replace(/[_-]/g, " ");
- seriesName = rename(parts[3] || "default");
- } else if (group === "Random Access" && parts.length === 2) {
- chartName = "RANDOM ACCESS";
- seriesName = rename(parts[1] || "default");
- } else {
- seriesName = rename(parts[1] || "default");
- chartName = formatQuery(parts[0]);
- }
- chartName = normalizeChartName(group, chartName);
- if (chartName.includes("PARQUET-UNC")) return;
-
- // Skip throughput metrics (keep only time/size)
- if (b.name.includes(" throughput")) return;
-
- let unit = b.unit;
- if (!unit) {
- if (b.name.toLowerCase().includes(" size/")) unit = "bytes";
- else if (b.name.toLowerCase().includes(" ratio ")) unit = "ratio";
- else unit = "ns";
- }
-
- const sortPos = parts[0].match(/q(\d+)$/i)?.[1]
- ? parseInt(RegExp.$1, 10)
- : 0;
- const idx = commitIdx.get(commit.id);
- if (idx === undefined) return;
-
- let chart = groups[group].get(chartName);
- if (!chart) {
- let displayUnit = unit;
- if (unit === "ns") displayUnit = "ms/iter";
- else if (unit === "bytes") displayUnit = "MiB";
- chart = {
- sort_position: sortPos,
- commits,
- unit: displayUnit,
- series: new Map(),
- };
- groups[group].set(chartName, chart);
- }
-
- if (!chart.series.has(seriesName)) {
- chart.series.set(seriesName, Array(commits.length).fill(null));
- }
-
- // Convert values: ns -> ms, bytes -> MiB
- let val = b.value;
- if (unit === "ns" && typeof val === "number") {
- val = val / 1e6; // ns to ms
- } else if (unit === "bytes" && typeof val === "number") {
- val = val / (1024 * 1024); // bytes to MiB
- }
-
- chart.series.get(seriesName)[idx] = { value: val };
- });
-
- console.log(
- `Processed ${benchmarkCount} benchmarks, ${commitsArr.length} commits`,
- );
-
- // Log uncategorized benchmarks for debugging
- if (uncategorized.size > 0) {
- console.log(
- `Uncategorized benchmark prefixes (${uncategorized.size}):`,
- [...uncategorized].slice(0, 20).join(", "),
- );
- }
-
- // Trim leading empty commits
- let firstIdx = commits.length;
- for (const gc of Object.values(groups)) {
- for (const cd of gc.values()) {
- for (const sd of cd.series.values()) {
- const i = sd.findIndex((d) => d !== null);
- if (i !== -1 && i < firstIdx) firstIdx = i;
- }
- }
- }
-
- if (firstIdx > 0 && firstIdx < commits.length) {
- console.log(`Trimming ${firstIdx} empty commits`);
- commits.splice(0, firstIdx);
- for (const gc of Object.values(groups)) {
- for (const cd of gc.values()) {
- cd.commits = commits;
- for (const [k, v] of cd.series) cd.series.set(k, v.slice(firstIdx));
- }
- }
- }
-
- // Sort charts within groups
- for (const gc of Object.values(groups)) {
- const sorted = [...gc.entries()].sort(
- (a, b) =>
- a[1].sort_position - b[1].sort_position || a[0].localeCompare(b[0]),
- );
- gc.clear();
- for (const [k, v] of sorted) gc.set(k, v);
- }
-
- // Precompute downsampled versions
- const downsampled = {};
- for (const [gn, gc] of Object.entries(groups)) {
- downsampled[gn] = {};
- for (const [cn, cd] of gc) {
- downsampled[gn][cn] = {
- "1x": cd,
- "2x": downsample(cd, 2),
- "4x": downsample(cd, 4),
- "8x": downsample(cd, 8),
- };
- }
- }
-
- // Count charts per group for logging
- const groupCounts = Object.entries(groups)
- .map(([n, g]) => `${n}: ${g.size}`)
- .filter((s) => !s.endsWith(": 0"));
- console.log("Charts per group:", groupCounts.join(", "));
-
- store = {
- commits,
- groups,
- metadata: buildMeta(groups, commits),
- downsampled,
- lastUpdated: new Date().toISOString(),
- };
- console.log(
- `Refresh done in ${Date.now() - t0}ms (${missing} missing commits)`,
- );
- } catch (e) {
- console.error("Refresh error:", e);
- }
-}
-
-// Summary calculations
-function latestIdx(chart) {
- for (let i = chart.commits.length - 1; i >= 0; i--) {
- for (const s of chart.series.values()) if (s[i]?.value != null) return i;
- }
- return -1;
-}
-
-function calcSummary(name, charts) {
- if (name === "Random Access") {
- for (const q of charts.values()) {
- const i = latestIdx(q);
- if (i === -1) continue;
- const vals = new Map();
- for (const [n, d] of q.series)
- if (d[i]?.value != null) vals.set(n, d[i].value);
- if (!vals.size) continue;
- const min = Math.min(...vals.values());
- return {
- type: "randomAccess",
- title: "Random Access Performance",
- rankings: [...vals]
- .map(([n, t]) => ({ name: n, time: t, ratio: t / min }))
- .sort((a, b) => a.time - b.time),
- explanation: "Random access time | Ratio to fastest (lower is better)",
- };
- }
- return null;
- }
-
- if (name === "Compression") {
- const cc = charts.get("VORTEX:PARQUET ZSTD RATIO COMPRESS TIME");
- const dc = charts.get("VORTEX:PARQUET ZSTD RATIO DECOMPRESS TIME");
- if (!cc && !dc) return null;
- const i = latestIdx(cc || dc);
- if (i === -1) return null;
- const collect = (c) =>
- c
- ? [...c.series]
- .filter(([n]) => !n.toLowerCase().includes("wide table"))
- .map(([, d]) => d[i]?.value)
- .filter((v) => v > 0)
- .map((v) => 1 / v)
- : [];
- return {
- type: "compression",
- title: "Compression Throughput vs Parquet",
- compressRatio: geoMean(collect(cc)),
- decompressRatio: geoMean(collect(dc)),
- datasetCount: collect(cc).length,
- explanation:
- "Inverse geomean of Vortex/Parquet ratios (higher is better)",
- };
- }
-
- if (name === "Compression Size") {
- const c = charts.get("VORTEX:PARQUET ZSTD SIZE");
- if (!c) return null;
- const i = latestIdx(c);
- if (i === -1) return null;
- const ratios = [...c.series]
- .filter(([n]) => !n.toLowerCase().includes("wide table"))
- .map(([, d]) => d[i]?.value)
- .filter((v) => v > 0);
- return ratios.length
- ? {
- type: "compressionSize",
- title: "Compression Size Summary",
- minRatio: Math.min(...ratios),
- meanRatio: geoMean(ratios),
- maxRatio: Math.max(...ratios),
- datasetCount: ratios.length,
- explanation:
- "Geomean of Vortex/Parquet size ratios (lower is better)",
- }
- : null;
- }
-
- if (
- QUERY_SUITES.some(
- (s) =>
- !s.skip &&
- (name === s.displayName || name.startsWith(s.displayName + " ")),
- )
- ) {
- const all = new Map();
- for (const q of charts.values())
- for (const n of q.series.keys()) if (!all.has(n)) all.set(n, new Map());
- for (const [qn, qd] of charts) {
- for (const [sn, sd] of qd.series) {
- for (let i = sd.length - 1; i >= 0; i--) {
- if (sd[i]?.value != null) {
- all.get(sn).set(qn, sd[i].value);
- break;
- }
- }
- }
- }
- if (!all.size) return null;
-
- const scores = new Map();
- for (const [sn, qr] of all) {
- let total = 0,
- max = 0;
- for (const v of qr.values()) {
- total += v;
- max = Math.max(max, v);
- }
- const penalty = Math.max(300000, max) * 2;
- const ratios = [];
- for (const qn of charts.keys()) {
- let base = Infinity;
- for (const m of all.values())
- if (m.has(qn)) base = Math.min(base, m.get(qn));
- if (base < Infinity)
- ratios.push((10 + (qr.get(qn) ?? penalty)) / (10 + base));
- }
- if (ratios.length)
- scores.set(sn, { score: geoMean(ratios), totalRuntime: total });
- }
-
- return scores.size
- ? {
- type: "queryBenchmark",
- title: "Performance Summary",
- rankings: [...scores]
- .map(([n, d]) => ({ name: n, ...d }))
- .sort((a, b) => a.score - b.score),
- explanation:
- "Geomean of query time ratio to fastest (lower is better)",
- }
- : null;
- }
- return null;
-}
-
-function buildMeta(groups, commits) {
- const meta = {};
- for (const [gn, gc] of Object.entries(groups)) {
- const charts = [...gc].map(([cn, cd]) => {
- const latest = {};
- for (const [sn, sd] of cd.series) {
- for (let i = sd.length - 1; i >= 0; i--)
- if (sd[i]?.value != null) {
- latest[sn] = sd[i].value;
- break;
- }
- }
- return {
- name: cn,
- unit: cd.unit,
- series: [...cd.series.keys()],
- sortPosition: cd.sort_position,
- totalPoints: cd.commits.length,
- latestValues: latest,
- };
- });
- meta[gn] = {
- charts,
- totalCharts: charts.length,
- hasData: charts.length > 0,
- summary: calcSummary(gn, gc),
- };
- }
- return {
- groups: meta,
- totalCommits: commits.length,
- commits: commits.map((c) => ({
- id: c.id,
- message: c.message?.split("\n")[0] || "",
- timestamp: c.timestamp,
- author: c.author?.name || "Unknown",
- })),
- lastUpdated: new Date().toISOString(),
- };
-}
-
-// HTTP handlers
-const json = (res, code, data) => {
- res.writeHead(code, {
- "Content-Type": "application/json",
- "Access-Control-Allow-Origin": "*",
- });
- res.end(JSON.stringify(data));
-};
-
-function serveFile(res, fp) {
- fs.readFile(fp, (err, data) => {
- if (err) {
- res.writeHead(err.code === "ENOENT" ? 404 : 500);
- return res.end(err.code === "ENOENT" ? "Not Found" : "Error");
- }
- const ext = path.extname(fp).toLowerCase();
- const hdrs = { "Content-Type": MIME[ext] || "application/octet-stream" };
- if (ext === ".js") {
- hdrs["Cache-Control"] = "no-cache";
- hdrs["Pragma"] = "no-cache";
- }
- res.writeHead(200, hdrs);
- res.end(data);
- });
-}
-
-function handleData(res, group, chart, start, end, last, startIdx, endIdx) {
- if (!store.downsampled) return json(res, 503, { error: "Loading" });
- const gd = store.downsampled[group];
- if (!gd) return json(res, 404, { error: "Group not found" });
- const cv = gd[chart];
- if (!cv) return json(res, 404, { error: "Chart not found" });
-
- const full = cv["1x"];
- const ts = (c) =>
- typeof c?.timestamp === "number"
- ? c.timestamp
- : new Date(c?.timestamp).getTime();
-
- let si = 0,
- ei = full.commits.length - 1;
-
- // Support "last=N" parameter to get the last N commits
- if (last && !start && !end && startIdx === null && endIdx === null) {
- const n = parseInt(last, 10);
- if (n > 0 && n < full.commits.length) {
- si = full.commits.length - n;
- }
- } else if (startIdx !== null || endIdx !== null) {
- // Support index-based range (startIdx, endIdx)
- if (startIdx !== null) si = Math.max(0, parseInt(startIdx, 10));
- if (endIdx !== null)
- ei = Math.min(full.commits.length - 1, parseInt(endIdx, 10));
- } else {
- // Timestamp-based range
- if (start) {
- const t = +start,
- i = full.commits.findIndex((c) => ts(c) >= t);
- if (i !== -1) si = i;
- }
- if (end) {
- const t = +end;
- for (let i = ei; i >= 0; i--)
- if (ts(full.commits[i]) <= t) {
- ei = i;
- break;
- }
- }
- }
-
- const len = ei - si + 1;
- const ver =
- len <= MAX_POINTS
- ? "1x"
- : len <= MAX_POINTS * 2
- ? "2x"
- : len <= MAX_POINTS * 4
- ? "4x"
- : "8x";
- const cd = cv[ver];
- const val = (d) => d?.value ?? (typeof d === "number" ? d : null);
-
- let commits, series;
- if (ver === "1x") {
- commits = full.commits.slice(si, ei + 1);
- series = Object.fromEntries(
- [...full.series].map(([n, d]) => [n, d.slice(si, ei + 1).map(val)]),
- );
- } else {
- const s = +ver[0],
- dsi = Math.floor(si / s),
- dei = Math.min(Math.ceil(ei / s), cd.commits.length - 1);
- commits = cd.commits.slice(dsi, dei + 1);
- series = Object.fromEntries(
- [...cd.series].map(([n, d]) => [n, d.slice(dsi, dei + 1).map(val)]),
- );
- }
-
- json(res, 200, {
- group,
- chart,
- unit: cd.unit,
- downsampleLevel: ver,
- originalLength: full.commits.length,
- requestedRange: { startIndex: si, endIndex: ei, length: len },
- commits: commits.map((c) => ({
- id: c.id,
- message: c.message?.split("\n")[0] || "",
- timestamp: c.timestamp,
- author: c.author?.name || "Unknown",
- url: c.url,
- })),
- series,
- });
-}
-
-const server = http.createServer((req, res) => {
- const [path_, qs] = req.url.split("?");
- const params = new URLSearchParams(qs || "");
-
- if (req.method === "OPTIONS") {
- res.writeHead(204, {
- "Access-Control-Allow-Origin": "*",
- "Access-Control-Allow-Methods": "GET",
- "Access-Control-Allow-Headers": "Content-Type",
- });
- return res.end();
- }
-
- if (path_ === "/api/metadata")
- return store.metadata
- ? json(res, 200, store.metadata)
- : json(res, 503, { error: "Loading" });
-
- if (path_.startsWith("/api/data/")) {
- const p = path_.slice(10).split("/");
- return handleData(
- res,
- decodeURIComponent(p[0] || ""),
- decodeURIComponent(p.slice(1).join("/") || ""),
- params.get("start"),
- params.get("end"),
- params.get("last"),
- params.has("startIdx") ? params.get("startIdx") : null,
- params.has("endIdx") ? params.get("endIdx") : null,
- );
- }
-
- const fp = path.join(__dirname, "dist", path_ === "/" ? "index.html" : path_);
- if (!fp.startsWith(__dirname) || fp.includes("/sample/")) {
- res.writeHead(403);
- return res.end("Forbidden");
- }
- serveFile(res, fp);
-});
-
-async function start() {
- console.log("Starting server...");
- await refresh();
- setInterval(refresh, REFRESH_INTERVAL);
- server.listen(PORT, () => console.log(`Server at http://localhost:${PORT}`));
-}
-
-start().catch(console.error);
diff --git a/benchmarks-website/src/App.jsx b/benchmarks-website/src/App.jsx
deleted file mode 100644
index 0df05bebf01..00000000000
--- a/benchmarks-website/src/App.jsx
+++ /dev/null
@@ -1,295 +0,0 @@
-import React, { useState, useEffect, useCallback, useMemo, useRef } from 'react';
-import Header from './components/Header';
-import Sidebar from './components/Sidebar';
-import BenchmarkSection from './components/BenchmarkSection';
-import Modal from './components/Modal';
-import { fetchMetadata } from './api';
-import { BENCHMARK_CONFIGS, CATEGORY_TAGS } from './config';
-
-export default function App() {
- const [metadata, setMetadata] = useState(null);
- const [loading, setLoading] = useState(true);
- const [error, setError] = useState(null);
- const [expandedGroups, setExpandedGroups] = useState(new Set());
- const [sidebarOpen, setSidebarOpen] = useState(false);
- const [categoryFilter, setCategoryFilter] = useState('all');
- const [searchFilter, setSearchFilter] = useState('');
- const [viewMode, setViewMode] = useState('grid');
- const [modalChart, setModalChart] = useState(null);
- const [showBackToTop, setShowBackToTop] = useState(false);
- const metadataFetched = useRef(false);
-
- useEffect(() => {
- if (metadataFetched.current) return;
- metadataFetched.current = true;
-
- async function loadMetadata() {
- try {
- const data = await fetchMetadata();
- setMetadata(data);
- const params = new URLSearchParams(window.location.search);
- if (params.get('expanded') === 'true' && data?.groups) {
- setExpandedGroups(new Set(Object.keys(data.groups)));
- }
- } catch (err) {
- setError(err.message);
- } finally {
- setLoading(false);
- }
- }
- loadMetadata();
- }, []);
-
- useEffect(() => {
- const handleScroll = () => {
- setShowBackToTop(window.scrollY > 400);
- };
- window.addEventListener('scroll', handleScroll, { passive: true });
- return () => window.removeEventListener('scroll', handleScroll);
- }, []);
-
- // Handle hash-based navigation on page load
- useEffect(() => {
- if (!metadata || loading) return;
-
- const hash = window.location.hash;
- if (hash && hash.startsWith('#group-')) {
- const groupId = hash.slice(1); // Remove the '#'
- const groupName = groupId.replace('group-', '').replace(/-/g, ' ');
-
- // Find the matching group (case-insensitive, handle hyphenated names)
- const matchingGroup = Object.keys(metadata.groups).find(name =>
- name.replace(/\s+/g, '-') === groupId.replace('group-', '')
- );
-
- if (matchingGroup) {
- // Expand the group
- setExpandedGroups(prev => new Set([...prev, matchingGroup]));
-
- // Scroll to the element after a short delay to allow rendering
- setTimeout(() => {
- const element = document.getElementById(groupId);
- if (element) {
- const headerHeight = 72;
- const y = element.getBoundingClientRect().top + window.scrollY - headerHeight - 16;
- window.scrollTo({ top: y, behavior: 'smooth' });
- }
- }, 100);
- }
- }
- }, [metadata, loading]);
-
- // Get benchmark config by group name
- const getBenchmarkConfig = useCallback((groupName) => {
- return BENCHMARK_CONFIGS.find(c => c.name === groupName) || {};
- }, []);
-
- // Filter groups based on category and search
- const filteredGroups = useMemo(() => {
- if (!metadata?.groups) return [];
-
- return Object.keys(metadata.groups).filter(groupName => {
- // Category filter
- if (categoryFilter !== 'all') {
- const tags = CATEGORY_TAGS[groupName] || [];
- if (!tags.includes(categoryFilter)) return false;
- }
-
- // Search filter
- if (searchFilter) {
- const searchLower = searchFilter.toLowerCase();
- const matchesGroup = groupName.toLowerCase().includes(searchLower);
- const groupData = metadata.groups[groupName];
- const charts = groupData?.charts || [];
- const matchesChart = charts.some(c =>
- c.name.toLowerCase().includes(searchLower)
- );
- if (!matchesGroup && !matchesChart) return false;
- }
-
- return true;
- });
- }, [metadata, categoryFilter, searchFilter]);
-
- // Toggle group expansion
- const toggleGroup = useCallback((groupName) => {
- setExpandedGroups(prev => {
- const next = new Set(prev);
- if (next.has(groupName)) {
- next.delete(groupName);
- } else {
- next.add(groupName);
- }
- return next;
- });
- }, []);
-
- // Expand all groups
- const expandAll = useCallback(() => {
- if (metadata?.groups) {
- setExpandedGroups(new Set(Object.keys(metadata.groups)));
- const url = new URL(window.location);
- url.searchParams.set('expanded', 'true');
- window.history.replaceState(null, '', url);
- }
- }, [metadata]);
-
- // Collapse all groups
- const collapseAll = useCallback(() => {
- setExpandedGroups(new Set());
- const url = new URL(window.location);
- url.searchParams.delete('expanded');
- window.history.replaceState(null, '', url);
- }, []);
-
- // Scroll to group
- const scrollToGroup = useCallback((groupName) => {
- const element = document.getElementById(`group-${groupName.replace(/\s+/g, '-')}`);
- if (element) {
- const headerHeight = 72;
- const y = element.getBoundingClientRect().top + window.scrollY - headerHeight - 16;
- window.scrollTo({ top: y, behavior: 'smooth' });
- }
- setSidebarOpen(false);
- }, []);
-
- // Back to top
- const scrollToTop = useCallback(() => {
- window.scrollTo({ top: 0, behavior: 'smooth' });
- }, []);
-
- // Clear search
- const clearFilter = useCallback(() => {
- setSearchFilter('');
- setCategoryFilter('all');
- }, []);
-
- if (loading) {
- return (
-
-
setSidebarOpen(!sidebarOpen)}
- categoryFilter={categoryFilter}
- onCategoryChange={setCategoryFilter}
- searchFilter={searchFilter}
- onSearchChange={setSearchFilter}
- viewMode={viewMode}
- onViewModeChange={setViewMode}
- onExpandAll={expandAll}
- onCollapseAll={collapseAll}
- />
-
-
-
-
-
Loading benchmarks...
-
-
-
-
- );
- }
-
- if (error) {
- return (
-
-
setSidebarOpen(!sidebarOpen)}
- categoryFilter={categoryFilter}
- onCategoryChange={setCategoryFilter}
- searchFilter={searchFilter}
- onSearchChange={setSearchFilter}
- viewMode={viewMode}
- onViewModeChange={setViewMode}
- onExpandAll={expandAll}
- onCollapseAll={collapseAll}
- />
-
-
-
-
Error loading benchmarks: {error}
-
-
-
-
- );
- }
-
- return (
-
-
setSidebarOpen(!sidebarOpen)}
- categoryFilter={categoryFilter}
- onCategoryChange={setCategoryFilter}
- searchFilter={searchFilter}
- onSearchChange={setSearchFilter}
- viewMode={viewMode}
- onViewModeChange={setViewMode}
- onExpandAll={expandAll}
- onCollapseAll={collapseAll}
- />
-
-
-
setSidebarOpen(false)}
- onGroupClick={scrollToGroup}
- onClearFilter={clearFilter}
- showClearFilter={categoryFilter !== 'all' || searchFilter !== ''}
- />
-
- setSidebarOpen(false)}
- />
-
-
- {filteredGroups.map(groupName => {
- const groupData = metadata.groups[groupName] || {};
- const charts = groupData.charts || [];
- const config = getBenchmarkConfig(groupName);
- const isExpanded = expandedGroups.has(groupName);
-
- if (config.hidden) return null;
-
- return (
- toggleGroup(groupName)}
- viewMode={viewMode}
- onFullscreen={(chartData) => setModalChart(chartData)}
- commitRange={metadata.totalCommits}
- summary={groupData.summary}
- />
- );
- })}
-
-
-
- {showBackToTop && (
-
- ↑
-
- )}
-
- {modalChart && (
- setModalChart(null)}
- />
- )}
-
- );
-}
diff --git a/benchmarks-website/src/api.js b/benchmarks-website/src/api.js
deleted file mode 100644
index 042ea7a6f0b..00000000000
--- a/benchmarks-website/src/api.js
+++ /dev/null
@@ -1,41 +0,0 @@
-const API_BASE = '';
-
-export async function fetchMetadata() {
- const response = await fetch(`${API_BASE}/api/metadata`);
- if (!response.ok) throw new Error(`Failed to fetch metadata: ${response.status}`);
- return response.json();
-}
-
-export async function fetchChartData(groupName, chartName, options = {}) {
- const { startTimestamp, endTimestamp, last, startIdx, endIdx } = options;
- let url = `${API_BASE}/api/data/${encodeURIComponent(groupName)}/${encodeURIComponent(chartName)}`;
- const params = new URLSearchParams();
-
- if (last) {
- params.set('last', last);
- } else if (startIdx !== undefined || endIdx !== undefined) {
- // Index-based range
- if (startIdx !== undefined) params.set('startIdx', startIdx);
- if (endIdx !== undefined) params.set('endIdx', endIdx);
- } else {
- // Timestamp-based range
- if (startTimestamp) {
- const ts = typeof startTimestamp === 'number'
- ? startTimestamp
- : new Date(startTimestamp).getTime();
- params.set('start', ts);
- }
- if (endTimestamp) {
- const ts = typeof endTimestamp === 'number'
- ? endTimestamp
- : new Date(endTimestamp).getTime();
- params.set('end', ts);
- }
- }
-
- if (params.toString()) url += '?' + params.toString();
-
- const response = await fetch(url);
- if (!response.ok) throw new Error(`Failed to fetch chart data: ${response.status}`);
- return response.json();
-}
diff --git a/benchmarks-website/src/components/BenchmarkSection.jsx b/benchmarks-website/src/components/BenchmarkSection.jsx
deleted file mode 100644
index 706a9c27fe6..00000000000
--- a/benchmarks-website/src/components/BenchmarkSection.jsx
+++ /dev/null
@@ -1,147 +0,0 @@
-import React, { useState, useCallback, useMemo } from 'react';
-import { Info, Link2 } from 'lucide-react';
-import ChartContainer from './ChartContainer';
-import BenchmarkSummary from './BenchmarkSummary';
-import { getBenchmarkDescription, remapChartName } from '../utils';
-
-export default function BenchmarkSection({
- groupName,
- charts,
- config,
- isExpanded,
- onToggle,
- viewMode,
- onFullscreen,
- commitRange,
- summary,
-}) {
- const [engineFilter, setEngineFilter] = useState('all');
- const [copiedLink, setCopiedLink] = useState(false);
-
- // Get unique engines from chart series
- const engines = useMemo(() => {
- const engineSet = new Set();
- charts.forEach(chart => {
- chart.series?.forEach(seriesName => {
- if (seriesName.includes(':')) {
- const engine = seriesName.split(':')[0].toLowerCase();
- engineSet.add(engine);
- }
- });
- });
- return Array.from(engineSet).sort();
- }, [charts]);
-
- // Filter and sort charts based on config
- const filteredCharts = useMemo(() => {
- if (!charts) return [];
-
- let result = charts.filter(chart => {
- // Apply keptCharts filter
- if (config.keptCharts) {
- const upperName = chart.name.toUpperCase();
- return config.keptCharts.some(kept => upperName === kept.toUpperCase());
- }
- return true;
- });
-
- // Sort by keptCharts order if specified
- if (config.keptCharts) {
- const orderMap = new Map(config.keptCharts.map((name, idx) => [name.toUpperCase(), idx]));
- result.sort((a, b) => {
- const aIdx = orderMap.get(a.name.toUpperCase()) ?? 999;
- const bIdx = orderMap.get(b.name.toUpperCase()) ?? 999;
- return aIdx - bIdx;
- });
- }
-
- return result;
- }, [charts, config]);
-
- // Copy link to clipboard
- const handleCopyLink = useCallback((e) => {
- e.stopPropagation();
- const url = `${window.location.origin}${window.location.pathname}#group-${groupName.replace(/\s+/g, '-')}`;
- navigator.clipboard.writeText(url);
- setCopiedLink(true);
- setTimeout(() => setCopiedLink(false), 2000);
- }, [groupName]);
-
- const description = getBenchmarkDescription(groupName);
- const hasData = filteredCharts.length > 0;
- const chartCount = filteredCharts.length;
-
- return (
-
-
-
-
{isExpanded ? '▼' : '▶'}
-
-
- {groupName}
-
-
-
-
- {description && (
-
-
-
- )}
-
- {chartCount} {chartCount === 1 ? 'CHART' : 'CHARTS'}
-
-
-
-
- {isExpanded && engines.length > 0 && (
-
- Filter by engine:
- setEngineFilter('all')}
- >
- All
-
- {engines.map(engine => (
- setEngineFilter(engine)}
- >
- {engine}
-
- ))}
-
- )}
-
-
-
-
- {isExpanded && (
-
- {filteredCharts.map(chart => (
-
- ))}
-
- )}
-
- );
-}
diff --git a/benchmarks-website/src/components/BenchmarkSummary.jsx b/benchmarks-website/src/components/BenchmarkSummary.jsx
deleted file mode 100644
index 6bc2d4f1790..00000000000
--- a/benchmarks-website/src/components/BenchmarkSummary.jsx
+++ /dev/null
@@ -1,129 +0,0 @@
-import React from 'react';
-import { formatTime } from '../utils';
-
-// BenchmarkSummary now uses pre-computed summary from metadata (passed via props)
-// instead of fetching all chart data
-export default function BenchmarkSummary({ groupName, charts, summary }) {
- // Use pre-computed summary from metadata
- const summaryData = summary;
-
- if (!summaryData) return null;
-
- // Query benchmarks (Clickbench, TPC-H, TPC-DS, etc.)
- if (summaryData.type === 'queryBenchmark' && summaryData.rankings?.length > 0) {
- return (
-
-
{summaryData.title || 'Performance Summary'}
-
- {summaryData.rankings.map((item, idx) => (
-
- #{idx + 1}
- {item.name}
-
- {item.score.toFixed(2)}x
- {formatTime(item.totalRuntime)}
-
-
- ))}
-
-
- {summaryData.explanation || 'Score: geometric mean of query time ratio to fastest (lower is better)'}
-
-
- );
- }
-
- if (summaryData.type === 'randomAccess' && summaryData.rankings?.length > 0) {
- return (
-
-
{summaryData.title || 'Random Access Performance'}
-
- {summaryData.rankings.map((item, idx) => (
-
- #{idx + 1}
- {item.name}
-
- {formatTime(item.time)}
- {item.ratio.toFixed(2)}x
-
-
- ))}
-
-
- {summaryData.explanation || 'Random access time | Ratio to fastest (lower is better)'}
-
-
- );
- }
-
- if (summaryData.type === 'compression') {
- return (
-
-
{summaryData.title || 'Compression Throughput vs Parquet'}
-
- {summaryData.compressRatio && (
-
- ⚡
- Write Speed (Compression)
-
- {summaryData.compressRatio.toFixed(2)}x
-
-
- )}
- {summaryData.decompressRatio && (
-
- 📤
- Scan Speed (Decompression)
-
- {summaryData.decompressRatio.toFixed(2)}x
-
-
- )}
-
-
- {summaryData.explanation || `Inverse geometric mean of Vortex/Parquet ratios across ${summaryData.datasetCount || 'multiple'} datasets (higher is better)`}
-
-
- );
- }
-
- if (summaryData.type === 'compressionSize' && summaryData.meanRatio) {
- return (
-
-
{summaryData.title || 'Compression Size Summary'}
-
- {summaryData.minRatio && (
-
- ⬇️
- Min Size Ratio
-
- {summaryData.minRatio.toFixed(2)}x
-
-
- )}
-
- 📊
- Mean Size Ratio
-
- {summaryData.meanRatio.toFixed(2)}x
-
-
- {summaryData.maxRatio && (
-
- ⬆️
- Max Size Ratio
-
- {summaryData.maxRatio.toFixed(2)}x
-
-
- )}
-
-
- {summaryData.explanation || `Geometric mean of Vortex/Parquet size ratios across ${summaryData.datasetCount || 'multiple'} datasets (lower is better)`}
-
-
- );
- }
-
- return null;
-}
diff --git a/benchmarks-website/src/components/ChartContainer.jsx b/benchmarks-website/src/components/ChartContainer.jsx
deleted file mode 100644
index 1dfb193e836..00000000000
--- a/benchmarks-website/src/components/ChartContainer.jsx
+++ /dev/null
@@ -1,664 +0,0 @@
-import {
- CategoryScale,
- Chart as ChartJS,
- Legend,
- LinearScale,
- LineElement,
- PointElement,
- Title,
- Tooltip,
-} from 'chart.js';
-import zoomPlugin from 'chartjs-plugin-zoom';
-import {
- ChevronLeft,
- ChevronRight,
- Expand,
- MoveHorizontal,
- SkipBack,
- SkipForward,
- ZoomIn,
- ZoomOut,
-} from 'lucide-react';
-import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
-import { Line } from 'react-chartjs-2';
-import { fetchChartData } from '../api';
-import { formatDate, stringToColor } from '../utils';
-
-ChartJS.register(
- CategoryScale,
- LinearScale,
- PointElement,
- LineElement,
- Title,
- Tooltip,
- Legend,
- zoomPlugin
-);
-
-// Custom tooltip positioner - 50px from cursor, 50px above nearest point
-Tooltip.positioners.topCorner = function(elements, eventPosition) {
- const chart = this.chart;
- const chartCenter = (chart.chartArea.left + chart.chartArea.right) / 2;
- const chartVerticalCenter = (chart.chartArea.top + chart.chartArea.bottom) / 2;
- const isOnRightSide = eventPosition.x > chartCenter;
- const isOnTopSide = eventPosition.y < chartVerticalCenter;
-
- let x = isOnRightSide ? eventPosition.x - 150 : eventPosition.x + 150;
- let y = isOnTopSide ? chart.chartArea.top + 100 : chart.chartArea.bottom - 100;
- return {
- x,
- y,
- xAlign: isOnRightSide ? 'right' : 'left',
- yAlign: isOnTopSide ? 'top' : 'bottom',
- };
-};
-
-const DEFAULT_RANGE_SIZE = 100;
-
-export default function ChartContainer({
- groupName,
- chartName,
- displayName,
- unit,
- config,
- engineFilter,
- onFullscreen,
-}) {
- const [totalCommits, setTotalCommits] = useState(null);
- const [chartData, setChartData] = useState(null);
- const [loading, setLoading] = useState(true);
- const [error, setError] = useState(null);
- // viewRange stores the requested range: either { last: N } or { startIdx, endIdx }
- const [viewRange, setViewRange] = useState({ last: DEFAULT_RANGE_SIZE });
- const chartRef = useRef(null);
- const isResettingZoom = useRef(false);
-
- // Fetch data for the current view range
- useEffect(() => {
- let cancelled = false;
-
- async function loadData() {
- setLoading(true);
- setError(null);
-
- try {
- let options = {};
- if (viewRange.last) {
- // Initial load: get last N commits
- options = { last: viewRange.last };
- } else if (viewRange.startIdx !== undefined && viewRange.endIdx !== undefined) {
- // Navigation: use index-based range
- options = { startIdx: viewRange.startIdx, endIdx: viewRange.endIdx };
- }
-
- const data = await fetchChartData(groupName, chartName, options);
- if (!cancelled && data) {
- setChartData(data);
- if (data.originalLength) {
- setTotalCommits(data.originalLength);
- } else if (data.commits) {
- setTotalCommits(data.commits.length);
- }
- }
- } catch (err) {
- if (!cancelled) {
- setError(err.message);
- }
- } finally {
- if (!cancelled) {
- setLoading(false);
- }
- }
- }
-
- loadData();
-
- return () => {
- cancelled = true;
- };
- }, [groupName, chartName, viewRange]);
-
- // Compute display range info from chartData (for rendering only)
- const displayRangeInfo = useMemo(() => {
- if (!chartData) return { startIdx: 0, endIdx: 0, total: 0, rangeSize: 0 };
- const total = chartData.originalLength || chartData.commits?.length || 0;
- const rangeSize = chartData.commits?.length || 0;
- const req = chartData.requestedRange || {};
- const startIdx = req.startIndex ?? (total - rangeSize);
- const endIdx = req.endIndex ?? (total - 1);
- return { startIdx, endIdx, total, rangeSize };
- }, [chartData]);
-
- // Compute current range from viewRange state (for navigation calculations)
- const getCurrentRange = useCallback(() => {
- const total = totalCommits || 0;
- if (viewRange.last) {
- const rangeSize = Math.min(viewRange.last, total);
- return {
- startIdx: Math.max(0, total - rangeSize),
- endIdx: total - 1,
- total,
- rangeSize,
- };
- }
- const startIdx = viewRange.startIdx ?? 0;
- const endIdx = viewRange.endIdx ?? (total - 1);
- return {
- startIdx,
- endIdx,
- total,
- rangeSize: endIdx - startIdx + 1,
- };
- }, [viewRange, totalCommits]);
-
- const isAtStart = displayRangeInfo.startIdx === 0;
- const isAtEnd = displayRangeInfo.endIdx >= displayRangeInfo.total - 1;
- const currentRangeSize = displayRangeInfo.rangeSize;
-
- // Navigation handlers - use functional updates to get latest state
- const handleGoToStart = useCallback(() => {
- const range = getCurrentRange();
- if (range.startIdx === 0 || !range.total) return;
- setViewRange({
- startIdx: 0,
- endIdx: Math.min(range.rangeSize - 1, range.total - 1),
- });
- }, [getCurrentRange]);
-
- const handleGoToEnd = useCallback(() => {
- const range = getCurrentRange();
- if (range.endIdx >= range.total - 1 || !range.total) return;
- setViewRange({ last: range.rangeSize });
- }, [getCurrentRange]);
-
- const handleMoveBackward = useCallback(() => {
- const range = getCurrentRange();
- if (range.startIdx === 0 || !range.total) return;
- const moveAmount = Math.max(1, Math.floor(range.rangeSize / 2));
- const newStartIdx = Math.max(0, range.startIdx - moveAmount);
- const newEndIdx = newStartIdx + range.rangeSize - 1;
- setViewRange({
- startIdx: newStartIdx,
- endIdx: Math.min(newEndIdx, range.total - 1),
- });
- }, [getCurrentRange]);
-
- const handleMoveForward = useCallback(() => {
- const range = getCurrentRange();
- if (range.endIdx >= range.total - 1 || !range.total) return;
- const moveAmount = Math.max(1, Math.floor(range.rangeSize / 2));
- const newEndIdx = Math.min(range.total - 1, range.endIdx + moveAmount);
- const newStartIdx = Math.max(0, newEndIdx - range.rangeSize + 1);
- setViewRange({ startIdx: newStartIdx, endIdx: newEndIdx });
- }, [getCurrentRange]);
-
- const handleZoomIn = useCallback(() => {
- const range = getCurrentRange();
- if (!range.total || range.rangeSize <= 10) return;
- const center = Math.floor((range.startIdx + range.endIdx) / 2);
- const newRangeSize = Math.max(10, Math.floor(range.rangeSize / 2));
- const halfRange = Math.floor(newRangeSize / 2);
- let newStartIdx = center - halfRange;
- let newEndIdx = newStartIdx + newRangeSize - 1;
-
- // Clamp to bounds
- if (newStartIdx < 0) {
- newStartIdx = 0;
- newEndIdx = newRangeSize - 1;
- }
- if (newEndIdx >= range.total) {
- newEndIdx = range.total - 1;
- newStartIdx = Math.max(0, newEndIdx - newRangeSize + 1);
- }
-
- setViewRange({ startIdx: newStartIdx, endIdx: newEndIdx });
- }, [getCurrentRange]);
-
- const handleZoomOut = useCallback(() => {
- const range = getCurrentRange();
- if (!range.total) return;
- const center = Math.floor((range.startIdx + range.endIdx) / 2);
- const newRangeSize = Math.min(range.total, range.rangeSize * 2);
- const halfRange = Math.floor(newRangeSize / 2);
- let newStartIdx = center - halfRange;
- let newEndIdx = newStartIdx + newRangeSize - 1;
-
- // Clamp to bounds
- if (newStartIdx < 0) {
- newStartIdx = 0;
- newEndIdx = Math.min(newRangeSize - 1, range.total - 1);
- }
- if (newEndIdx >= range.total) {
- newEndIdx = range.total - 1;
- newStartIdx = Math.max(0, newEndIdx - newRangeSize + 1);
- }
-
- setViewRange({ startIdx: newStartIdx, endIdx: newEndIdx });
- }, [getCurrentRange]);
-
- const handleShowFullRange = useCallback(() => {
- const range = getCurrentRange();
- if (!range.total) return;
- setViewRange({ startIdx: 0, endIdx: range.total - 1 });
- }, [getCurrentRange]);
-
- const isFullRange = isAtStart && isAtEnd;
-
- // Handle drag selection zoom
- const handleDragZoom = useCallback((startDataIdx, endDataIdx) => {
- if (!chartData?.commits || !chartData.requestedRange) return;
-
- const numCommits = chartData.commits.length;
- if (numCommits < 2) return;
-
- const rangeStart = chartData.requestedRange.startIndex;
- const rangeEnd = chartData.requestedRange.endIndex;
- const total = chartData.originalLength || rangeEnd + 1;
-
- // Map chart indices to original dataset indices using linear interpolation
- // This correctly handles downsampled data where numCommits < (rangeEnd - rangeStart + 1)
- const minIdx = Math.min(startDataIdx, endDataIdx);
- const maxIdx = Math.max(startDataIdx, endDataIdx);
- const globalStartIdx = rangeStart + Math.round(minIdx / (numCommits - 1) * (rangeEnd - rangeStart));
- const globalEndIdx = rangeStart + Math.round(maxIdx / (numCommits - 1) * (rangeEnd - rangeStart));
-
- // Ensure minimum range
- if (globalEndIdx - globalStartIdx < 5) return;
-
- setViewRange({
- startIdx: Math.max(0, globalStartIdx),
- endIdx: Math.min(total - 1, globalEndIdx),
- });
- }, [chartData]);
-
- // Process series data with filters and renaming
- const processedData = useMemo(() => {
- if (!chartData?.series || !chartData?.commits) return null;
-
- const { series, commits } = chartData;
- const datasets = [];
- const labels = commits.map(c => formatDate(c.timestamp));
-
- Object.entries(series).forEach(([seriesName, points]) => {
- // Apply removed datasets filter
- if (config.removedDatasets?.has(seriesName)) return;
-
- // Apply engine filter
- if (engineFilter !== 'all') {
- const engine = seriesName.split(':')[0].toLowerCase();
- if (engine !== engineFilter && !seriesName.toLowerCase().includes(engineFilter)) {
- return;
- }
- }
-
- // Rename series if needed
- let displaySeriesName = seriesName;
- if (config.renamedDatasets) {
- const caseInsensitive = {};
- Object.entries(config.renamedDatasets).forEach(([k, v]) => {
- caseInsensitive[k.toLowerCase()] = v;
- });
- displaySeriesName = caseInsensitive[seriesName.toLowerCase()] || seriesName;
- }
-
- // Check if hidden by default
- const hidden = config.hiddenDatasets?.has(seriesName) ||
- config.hiddenDatasets?.has(displaySeriesName);
-
- datasets.push({
- label: displaySeriesName,
- data: points,
- borderColor: stringToColor(displaySeriesName),
- backgroundColor: stringToColor(displaySeriesName) + '20',
- pointRadius: 2,
- pointHoverRadius: 5,
- pointStyle: 'cross',
- borderWidth: 1.5,
- tension: 0,
- spanGaps: true,
- hidden,
- });
- });
-
- return { labels, datasets, commits };
- }, [chartData, config, engineFilter]);
-
- // Handle click on chart point to open commit on GitHub
- const handleChartClick = useCallback((event, elements) => {
- if (!elements.length || !processedData?.commits) return;
- const dataIndex = elements[0].index;
- const commit = processedData.commits[dataIndex];
- if (commit?.id) {
- window.open(`https://github.com/vortex-data/vortex/commit/${commit.id}`, '_blank');
- }
- }, [processedData]);
-
- // Chart.js options with drag zoom
- const options = useMemo(() => ({
- responsive: true,
- maintainAspectRatio: false,
- animation: false,
- onClick: handleChartClick,
- onHover: (event, elements) => {
- event.native.target.style.cursor = elements.length ? 'pointer' : 'default';
- },
- interaction: {
- mode: 'index',
- intersect: true,
- },
- plugins: {
- legend: {
- position: 'top',
- align: 'start',
- labels: {
- boxWidth: 12,
- padding: 8,
- font: {
- size: 12,
- family: 'Geist, sans-serif',
- },
- usePointStyle: true,
- pointStyle: 'rectRounded',
- },
- },
- tooltip: {
- backgroundColor: 'rgba(16, 16, 16, 0.9)',
- titleFont: { family: 'Geist, sans-serif', size: 13 },
- bodyFont: { family: 'Geist Mono, monospace', size: 12 },
- padding: 12,
- cornerRadius: 4,
- position: 'topCorner',
- caretSize: 0,
- itemSort: (a, b) => b.parsed.y - a.parsed.y,
- // Limit to top 10 items by value to prevent tooltip from getting too large
- filter: (item, _index, items) => {
- if (items.length <= 10) return item.parsed.y != null;
- const validItems = items.filter(i => i.parsed.y != null);
- if (validItems.length <= 10) return item.parsed.y != null;
- const sorted = [...validItems].sort((a, b) => (b.parsed.y ?? 0) - (a.parsed.y ?? 0));
- const top10 = sorted.slice(0, 10);
- return top10.some(i => i.datasetIndex === item.datasetIndex);
- },
- callbacks: {
- title: (items) => {
- if (!items.length || !processedData?.commits) return '';
- const commit = processedData.commits[items[0].dataIndex];
- if (!commit) return items[0].label;
- const author = commit.author || 'Unknown';
- return `${formatDate(commit.timestamp)} — ${author}\n(${commit.id?.slice(0, 7) || ''}) ${commit.message || ''}`;
- },
- label: (item) => {
- const value = item.parsed.y;
- if (value == null) return null;
- const formattedValue = value < 1 ? value.toFixed(4) : value.toFixed(2);
- return `${item.dataset.label}: ${formattedValue} ${unit || ''}`;
- },
- labelTextColor: (tooltipItem) => {
- const chart = tooltipItem.chart;
- const activeElements = chart._active || [];
- if (activeElements.length === 0) return '#ffffff';
- const lastEvent = chart._lastEvent;
- if (!lastEvent) return '#ffffff';
- // Find which dataset point is closest to the cursor
- let hoveredDatasetIndex = activeElements[0].datasetIndex;
- let closestDist = Infinity;
- for (const el of activeElements) {
- const point = chart.getDatasetMeta(el.datasetIndex).data[el.index];
- if (point) {
- const dist = Math.hypot(point.x - lastEvent.x, point.y - lastEvent.y);
- if (dist < closestDist) {
- closestDist = dist;
- hoveredDatasetIndex = el.datasetIndex;
- }
- }
- }
- if (tooltipItem.datasetIndex === hoveredDatasetIndex) {
- return '#ffffff';
- }
- return 'rgba(255, 255, 255, 0.45)';
- },
- },
- },
- zoom: {
- zoom: {
- drag: {
- enabled: true,
- backgroundColor: 'rgba(99, 102, 241, 0.2)',
- borderColor: 'rgba(99, 102, 241, 0.8)',
- borderWidth: 1,
- },
- mode: 'x',
- onZoomComplete: ({ chart }) => {
- // Prevent infinite loop from resetZoom triggering onZoomComplete
- if (isResettingZoom.current) {
- isResettingZoom.current = false;
- return;
- }
-
- const { min, max } = chart.scales.x;
- const startIdx = Math.floor(min);
- const endIdx = Math.ceil(max);
- if (startIdx >= 0 && endIdx > startIdx) {
- handleDragZoom(startIdx, endIdx);
- }
- // Reset chart zoom state
- isResettingZoom.current = true;
- chart.resetZoom();
- },
- },
- },
- },
- scales: {
- x: {
- display: true,
- grid: {
- display: true,
- color: 'rgba(166, 166, 166, 0.12)',
- },
- ticks: {
- maxRotation: 45,
- minRotation: 45,
- font: {
- size: 11,
- family: 'Geist, sans-serif',
- },
- maxTicksLimit: 10,
- callback: function(value, index, ticks) {
- // Always show first and last tick
- if (index === 0 || index === ticks.length - 1) {
- return this.getLabelForValue(value);
- }
- // Show intermediate ticks based on maxTicksLimit
- const step = Math.ceil(ticks.length / 10);
- if (index % step === 0) {
- return this.getLabelForValue(value);
- }
- return null;
- },
- },
- },
- y: {
- display: true,
- beginAtZero: true,
- grid: {
- color: 'rgba(166, 166, 166, 0.12)',
- },
- ticks: {
- font: {
- size: 12,
- family: 'Geist Mono, monospace',
- },
- },
- title: {
- display: !!unit,
- text: unit || '',
- font: {
- size: 12,
- family: 'Geist, sans-serif',
- },
- },
- },
- },
- }), [unit, processedData, handleDragZoom, handleChartClick]);
-
- // Fullscreen handler
- const handleFullscreen = useCallback(() => {
- if (processedData) {
- onFullscreen({
- title: displayName,
- groupName,
- chartName,
- unit,
- config,
- initialData: processedData,
- totalCommits,
- currentRange: getCurrentRange(),
- });
- }
- }, [processedData, displayName, groupName, chartName, unit, config, totalCommits, getCurrentRange, onFullscreen]);
-
- // Show placeholder only on initial load (no data yet)
- const showPlaceholder = !processedData && (loading || error);
- const showOverlay = loading && processedData;
-
- if (showPlaceholder) {
- return (
-
-
- {displayName}
-
-
- {error ? (
-
Error loading chart
- ) : (
-
- )}
-
-
- );
- }
-
- if (!loading && error) {
- return (
-
- );
- }
-
- if (!processedData || processedData.datasets.length === 0) {
- return (
-
- );
- }
-
- return (
-
-
-
- {displayName}
- {chartData?.downsampleLevel && chartData.downsampleLevel !== '1x' && (
-
- {chartData.downsampleLevel} downsampled
-
- )}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {showOverlay && (
-
- )}
-
-
- );
-}
diff --git a/benchmarks-website/src/components/Header.jsx b/benchmarks-website/src/components/Header.jsx
deleted file mode 100644
index b9624794119..00000000000
--- a/benchmarks-website/src/components/Header.jsx
+++ /dev/null
@@ -1,110 +0,0 @@
-import React from 'react';
-
-export default function Header({
- sidebarOpen,
- onMenuToggle,
- categoryFilter,
- onCategoryChange,
- searchFilter,
- onSearchChange,
- viewMode,
- onViewModeChange,
- onExpandAll,
- onCollapseAll,
-}) {
- return (
-
-
-
-
-
Vortex Benchmarks
-
-
-
-
- Expand All
-
-
- Collapse All
-
- onCategoryChange(e.target.value)}
- aria-label="Filter benchmarks by category"
- >
- All Benchmarks
- Read/Write
- Queries (NVMe)
- Queries (S3)
- TPC-H (SF=1)
- TPC-H (SF=10)
- TPC-H (SF=100)
- TPC-H (SF=1000)
- TPC-DS (SF=1)
- TPC-DS (SF=10)
-
- onSearchChange(e.target.value)}
- />
-
-
-
-
-
- onViewModeChange('grid')}
- aria-label="Grid view"
- >
- ⊞
-
- onViewModeChange('list')}
- aria-label="List view"
- >
- ☰
-
-
-
-
-
-
- GitHub
-
-
-
-
- );
-}
diff --git a/benchmarks-website/src/components/Modal.jsx b/benchmarks-website/src/components/Modal.jsx
deleted file mode 100644
index b9bb7d419b1..00000000000
--- a/benchmarks-website/src/components/Modal.jsx
+++ /dev/null
@@ -1,476 +0,0 @@
-import React, { useState, useEffect, useCallback, useMemo, useRef } from 'react';
-import { Line } from 'react-chartjs-2';
-import {
- SkipBack,
- ChevronLeft,
- ChevronRight,
- SkipForward,
- ZoomIn,
- ZoomOut,
- MoveHorizontal,
- X,
-} from 'lucide-react';
-import { fetchChartData } from '../api';
-import { stringToColor, formatDate } from '../utils';
-
-export default function Modal({ chartData, onClose }) {
- const [loading, setLoading] = useState(false);
- const [viewRange, setViewRange] = useState(null);
- const [currentData, setCurrentData] = useState(null);
- const [totalCommits, setTotalCommits] = useState(chartData?.totalCommits || 0);
- const chartRef = useRef(null);
- const isResettingZoom = useRef(false);
-
- // Initialize with the data passed from parent
- useEffect(() => {
- if (chartData?.initialData) {
- setCurrentData(chartData.initialData);
- setTotalCommits(chartData.totalCommits || chartData.initialData.commits?.length || 0);
- if (chartData.currentRange) {
- setViewRange({
- startIdx: chartData.currentRange.startIdx,
- endIdx: chartData.currentRange.endIdx,
- });
- }
- }
- }, [chartData]);
-
- // Close on escape key
- useEffect(() => {
- const handleKeyDown = (e) => {
- if (e.key === 'Escape') {
- onClose();
- }
- };
- document.addEventListener('keydown', handleKeyDown);
- return () => document.removeEventListener('keydown', handleKeyDown);
- }, [onClose]);
-
- // Prevent body scroll when modal is open
- useEffect(() => {
- document.body.style.overflow = 'hidden';
- return () => {
- document.body.style.overflow = '';
- };
- }, []);
-
- const handleBackdropClick = useCallback((e) => {
- if (e.target === e.currentTarget) {
- onClose();
- }
- }, [onClose]);
-
- // Fetch data for a new range
- const fetchRange = useCallback(async (range) => {
- if (!chartData?.groupName || !chartData?.chartName) return;
-
- setLoading(true);
- try {
- let options = {};
- if (range.last) {
- options = { last: range.last };
- } else if (range.startIdx !== undefined && range.endIdx !== undefined) {
- options = { startIdx: range.startIdx, endIdx: range.endIdx };
- }
-
- const data = await fetchChartData(chartData.groupName, chartData.chartName, options);
- if (data) {
- // Process the data similar to ChartContainer
- const processedData = processChartData(data, chartData.config);
- setCurrentData(processedData);
- if (data.originalLength) {
- setTotalCommits(data.originalLength);
- }
- }
- } catch (err) {
- console.error('Error fetching range:', err);
- } finally {
- setLoading(false);
- }
- }, [chartData]);
-
- // Process chart data (similar to ChartContainer)
- const processChartData = useCallback((data, config) => {
- if (!data?.series || !data?.commits) return null;
-
- const { series, commits } = data;
- const datasets = [];
- const labels = commits.map(c => formatDate(c.timestamp));
-
- Object.entries(series).forEach(([seriesName, points]) => {
- if (config?.removedDatasets?.has(seriesName)) return;
-
- let displaySeriesName = seriesName;
- if (config?.renamedDatasets) {
- const caseInsensitive = {};
- Object.entries(config.renamedDatasets).forEach(([k, v]) => {
- caseInsensitive[k.toLowerCase()] = v;
- });
- displaySeriesName = caseInsensitive[seriesName.toLowerCase()] || seriesName;
- }
-
- const dataPoints = points.map(p => p);
- const hidden = config?.hiddenDatasets?.has(seriesName) ||
- config?.hiddenDatasets?.has(displaySeriesName);
-
- datasets.push({
- label: displaySeriesName,
- data: dataPoints,
- borderColor: stringToColor(displaySeriesName),
- backgroundColor: stringToColor(displaySeriesName) + '20',
- pointRadius: 2,
- pointHoverRadius: 5,
- pointStyle: 'cross',
- borderWidth: 1.5,
- tension: 0,
- spanGaps: true,
- hidden,
- });
- });
-
- return { labels, datasets, commits };
- }, []);
-
- // Get current range info
- const getCurrentRange = useCallback(() => {
- if (!viewRange) {
- return { startIdx: 0, endIdx: totalCommits - 1, total: totalCommits, rangeSize: totalCommits };
- }
- const startIdx = viewRange.startIdx ?? 0;
- const endIdx = viewRange.endIdx ?? (totalCommits - 1);
- return {
- startIdx,
- endIdx,
- total: totalCommits,
- rangeSize: endIdx - startIdx + 1,
- };
- }, [viewRange, totalCommits]);
-
- const range = getCurrentRange();
- const isAtStart = range.startIdx === 0;
- const isAtEnd = range.endIdx >= range.total - 1;
- const currentRangeSize = range.rangeSize;
- const isFullRange = isAtStart && isAtEnd;
-
- // Navigation handlers
- const handleGoToStart = useCallback(() => {
- if (isAtStart || !range.total) return;
- const newRange = {
- startIdx: 0,
- endIdx: Math.min(currentRangeSize - 1, range.total - 1),
- };
- setViewRange(newRange);
- fetchRange(newRange);
- }, [isAtStart, currentRangeSize, range.total, fetchRange]);
-
- const handleGoToEnd = useCallback(() => {
- if (isAtEnd || !range.total) return;
- const newRange = { last: currentRangeSize };
- setViewRange({
- startIdx: range.total - currentRangeSize,
- endIdx: range.total - 1,
- });
- fetchRange(newRange);
- }, [isAtEnd, currentRangeSize, range.total, fetchRange]);
-
- const handleMoveBackward = useCallback(() => {
- if (isAtStart || !range.total) return;
- const moveAmount = Math.max(1, Math.floor(currentRangeSize / 2));
- const newStartIdx = Math.max(0, range.startIdx - moveAmount);
- const newEndIdx = newStartIdx + currentRangeSize - 1;
- const newRange = {
- startIdx: newStartIdx,
- endIdx: Math.min(newEndIdx, range.total - 1),
- };
- setViewRange(newRange);
- fetchRange(newRange);
- }, [isAtStart, range, currentRangeSize, fetchRange]);
-
- const handleMoveForward = useCallback(() => {
- if (isAtEnd || !range.total) return;
- const moveAmount = Math.max(1, Math.floor(currentRangeSize / 2));
- const newEndIdx = Math.min(range.total - 1, range.endIdx + moveAmount);
- const newStartIdx = Math.max(0, newEndIdx - currentRangeSize + 1);
- const newRange = { startIdx: newStartIdx, endIdx: newEndIdx };
- setViewRange(newRange);
- fetchRange(newRange);
- }, [isAtEnd, range, currentRangeSize, fetchRange]);
-
- const handleZoomIn = useCallback(() => {
- if (!range.total || currentRangeSize <= 10) return;
- const center = Math.floor((range.startIdx + range.endIdx) / 2);
- const newRangeSize = Math.max(10, Math.floor(currentRangeSize / 2));
- const halfRange = Math.floor(newRangeSize / 2);
- let newStartIdx = center - halfRange;
- let newEndIdx = newStartIdx + newRangeSize - 1;
-
- if (newStartIdx < 0) {
- newStartIdx = 0;
- newEndIdx = newRangeSize - 1;
- }
- if (newEndIdx >= range.total) {
- newEndIdx = range.total - 1;
- newStartIdx = Math.max(0, newEndIdx - newRangeSize + 1);
- }
-
- const newRange = { startIdx: newStartIdx, endIdx: newEndIdx };
- setViewRange(newRange);
- fetchRange(newRange);
- }, [range, currentRangeSize, fetchRange]);
-
- const handleZoomOut = useCallback(() => {
- if (!range.total) return;
- const center = Math.floor((range.startIdx + range.endIdx) / 2);
- const newRangeSize = Math.min(range.total, currentRangeSize * 2);
- const halfRange = Math.floor(newRangeSize / 2);
- let newStartIdx = center - halfRange;
- let newEndIdx = newStartIdx + newRangeSize - 1;
-
- if (newStartIdx < 0) {
- newStartIdx = 0;
- newEndIdx = Math.min(newRangeSize - 1, range.total - 1);
- }
- if (newEndIdx >= range.total) {
- newEndIdx = range.total - 1;
- newStartIdx = Math.max(0, newEndIdx - newRangeSize + 1);
- }
-
- const newRange = { startIdx: newStartIdx, endIdx: newEndIdx };
- setViewRange(newRange);
- fetchRange(newRange);
- }, [range, currentRangeSize, fetchRange]);
-
- const handleShowFullRange = useCallback(() => {
- if (!range.total) return;
- const newRange = { startIdx: 0, endIdx: range.total - 1 };
- setViewRange(newRange);
- fetchRange(newRange);
- }, [range.total, fetchRange]);
-
- // Handle drag selection zoom
- const handleDragZoom = useCallback((startDataIdx, endDataIdx) => {
- if (!currentData?.commits) return;
-
- const numCommits = currentData.commits.length;
- if (numCommits < 2) return;
-
- const rangeStart = range.startIdx;
- const rangeEnd = range.endIdx;
- const total = range.total;
-
- const minIdx = Math.min(startDataIdx, endDataIdx);
- const maxIdx = Math.max(startDataIdx, endDataIdx);
- const globalStartIdx = rangeStart + Math.round(minIdx / (numCommits - 1) * (rangeEnd - rangeStart));
- const globalEndIdx = rangeStart + Math.round(maxIdx / (numCommits - 1) * (rangeEnd - rangeStart));
-
- if (globalEndIdx - globalStartIdx < 5) return;
-
- const newRange = {
- startIdx: Math.max(0, globalStartIdx),
- endIdx: Math.min(total - 1, globalEndIdx),
- };
- setViewRange(newRange);
- fetchRange(newRange);
- }, [currentData, range, fetchRange]);
-
- // Chart options
- const options = useMemo(() => ({
- responsive: true,
- maintainAspectRatio: false,
- animation: false,
- interaction: {
- mode: 'index',
- intersect: false,
- },
- plugins: {
- legend: {
- position: 'top',
- align: 'start',
- labels: {
- boxWidth: 12,
- padding: 8,
- font: { size: 11, family: 'Geist, sans-serif' },
- usePointStyle: true,
- pointStyle: 'rectRounded',
- },
- },
- tooltip: {
- backgroundColor: 'rgba(16, 16, 16, 0.9)',
- titleFont: { family: 'Geist, sans-serif', size: 12 },
- bodyFont: { family: 'Geist Mono, monospace', size: 11 },
- padding: 12,
- cornerRadius: 4,
- caretSize: 0,
- position: 'topCorner',
- itemSort: (a, b) => b.parsed.y - a.parsed.y,
- callbacks: {
- title: (items) => {
- if (!items.length || !currentData?.commits) return '';
- const commit = currentData.commits[items[0].dataIndex];
- if (!commit) return items[0].label;
- const author = commit.author || 'Unknown';
- return `${formatDate(commit.timestamp)} — ${author}\n(${commit.id?.slice(0, 7) || ''}) ${commit.message || ''}`;
- },
- label: (item) => {
- const value = item.parsed.y;
- if (value == null) return null;
- const formattedValue = value < 1 ? value.toFixed(4) : value.toFixed(2);
- return `${item.dataset.label}: ${formattedValue} ${chartData?.unit || ''}`;
- },
- },
- },
- zoom: {
- zoom: {
- drag: {
- enabled: true,
- backgroundColor: 'rgba(99, 102, 241, 0.2)',
- borderColor: 'rgba(99, 102, 241, 0.8)',
- borderWidth: 1,
- },
- mode: 'x',
- onZoomComplete: ({ chart }) => {
- if (isResettingZoom.current) {
- isResettingZoom.current = false;
- return;
- }
- const { min, max } = chart.scales.x;
- const startIdx = Math.floor(min);
- const endIdx = Math.ceil(max);
- if (startIdx >= 0 && endIdx > startIdx) {
- handleDragZoom(startIdx, endIdx);
- }
- isResettingZoom.current = true;
- chart.resetZoom();
- },
- },
- },
- },
- scales: {
- x: {
- display: true,
- grid: { display: true, color: 'rgba(0, 0, 0, 0.12)' },
- ticks: {
- maxRotation: 45,
- minRotation: 45,
- font: { size: 10, family: 'Geist, sans-serif' },
- maxTicksLimit: 15,
- callback: function(value, index, ticks) {
- // Always show first and last tick
- if (index === 0 || index === ticks.length - 1) {
- return this.getLabelForValue(value);
- }
- // Show intermediate ticks based on maxTicksLimit
- const step = Math.ceil(ticks.length / 15);
- if (index % step === 0) {
- return this.getLabelForValue(value);
- }
- return null;
- },
- },
- },
- y: {
- display: true,
- beginAtZero: true,
- grid: { color: 'rgba(0, 0, 0, 0.12)' },
- ticks: { font: { size: 11, family: 'Geist Mono, monospace' } },
- title: {
- display: !!chartData?.unit,
- text: chartData?.unit || '',
- font: { size: 11, family: 'Geist, sans-serif' },
- },
- },
- },
- }), [currentData, chartData, handleDragZoom]);
-
- if (!chartData) return null;
-
- return (
-
-
-
-
{chartData.title}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {currentData && (
-
- )}
- {loading && (
-
- )}
-
-
-
- );
-}
diff --git a/benchmarks-website/src/components/Sidebar.jsx b/benchmarks-website/src/components/Sidebar.jsx
deleted file mode 100644
index 3a53b801f8e..00000000000
--- a/benchmarks-website/src/components/Sidebar.jsx
+++ /dev/null
@@ -1,59 +0,0 @@
-import React from 'react';
-
-export default function Sidebar({
- isOpen,
- groups,
- onClose,
- onGroupClick,
- onClearFilter,
- showClearFilter,
-}) {
- return (
-
-
-
-
Navigation
-
- ×
-
-
-
- {showClearFilter && (
-
- Clear Filter
-
- )}
-
-
-
-
-
-
- );
-}
diff --git a/benchmarks-website/src/config.js b/benchmarks-website/src/config.js
deleted file mode 100644
index dfe5555019d..00000000000
--- a/benchmarks-website/src/config.js
+++ /dev/null
@@ -1,285 +0,0 @@
-// =============================================================================
-// SQL query benchmark suites — single source of truth.
-// To add a new SQL query benchmark, add one entry to QUERY_SUITES.
-// The server (routing/formatting) and frontend (UI config) both derive from this.
-// =============================================================================
-
-export const QUERY_SUITES = [
- {
- prefix: "clickbench",
- displayName: "Clickbench",
- queryPrefix: "CLICKBENCH",
- description:
- "ClickHouse's analytical benchmark suite testing real-world query patterns on web analytics data",
- tags: ["Queries (NVMe)"],
- hiddenDatasets: ["datafusion:lance"],
- },
- {
- prefix: "clickbench-sorted",
- displayName: "Clickbench Sorted",
- queryPrefix: "CLICKBENCH SORTED",
- description:
- "ClickBench queries over data globally sorted by event date and event time",
- tags: ["Queries (NVMe)"],
- hiddenDatasets: ["datafusion:lance"],
- },
- {
- prefix: "statpopgen",
- displayName: "Statistical and Population Genetics",
- queryPrefix: "STATPOPGEN",
- description:
- "A suite of Statistical and Population genetics queries using the gnomAD dataset",
- tags: ["Queries (NVMe)", "StatPopGen"],
- },
- {
- prefix: "polarsignals",
- displayName: "PolarSignals Profiling",
- queryPrefix: "POLARSIGNALS",
- description:
- "Profiling data benchmark modeled on PolarSignals/Parca, exercising scan-layer performance with projection and filter pushdown on deeply nested schemas",
- tags: ["Queries (NVMe)", "PolarSignals"],
- },
- {
- prefix: "tpch",
- displayName: "TPC-H",
- queryPrefix: "TPC-H",
- datasetKey: "tpch",
- fanOut: true,
- hiddenDatasets: ["datafusion:lance"],
- },
- {
- prefix: "tpcds",
- displayName: "TPC-DS",
- queryPrefix: "TPC-DS",
- datasetKey: "tpcds",
- fanOut: true,
- },
- { prefix: "fineweb", skip: true },
-];
-
-// Pre-registered fan-out groups (storage x scale factor).
-export const FAN_OUT_GROUPS = [
- "TPC-H (NVMe) (SF=1)",
- "TPC-H (S3) (SF=1)",
- "TPC-H (NVMe) (SF=10)",
- "TPC-H (S3) (SF=10)",
- "TPC-H (NVMe) (SF=100)",
- "TPC-H (S3) (SF=100)",
- "TPC-H (NVMe) (SF=1000)",
- "TPC-H (S3) (SF=1000)",
- "TPC-DS (NVMe) (SF=1)",
- "TPC-DS (NVMe) (SF=10)",
-];
-
-// Canonical engine:format renaming used by all query suites.
-export const ENGINE_RENAMES = {
- "datafusion:vortex-file-compressed": "datafusion:vortex",
- "datafusion:parquet": "datafusion:parquet",
- "datafusion:arrow": "datafusion:in-memory-arrow",
- "datafusion:lance": "datafusion:lance",
- "datafusion:vortex-compact": "datafusion:vortex-compact",
- "duckdb:vortex-file-compressed": "duckdb:vortex",
- "duckdb:parquet": "duckdb:parquet",
- "duckdb:duckdb": "duckdb:duckdb",
- "duckdb:vortex-compact": "duckdb:vortex-compact",
- "vortex-tokio-local-disk": "vortex-nvme",
- "vortex-compact-tokio-local-disk": "vortex-compact-nvme",
- "lance-tokio-local-disk": "lance-nvme",
- "parquet-tokio-local-disk": "parquet-nvme",
- lance: "lance",
-};
-
-// =============================================================================
-// Below: frontend UI config, derived from QUERY_SUITES where possible.
-// =============================================================================
-
-// Build BENCHMARK_CONFIGS: bespoke non-query groups + generated query group entries.
-const BESPOKE_CONFIGS = [
- {
- name: "Random Access",
- renamedDatasets: {
- "vortex-tokio-local-disk": "vortex-nvme",
- "vortex-compact-tokio-local-disk": "vortex-compact-nvme",
- "lance-tokio-local-disk": "lance-nvme",
- "parquet-tokio-local-disk": "parquet-nvme",
- },
- },
- {
- name: "Compression",
- keptCharts: [
- "COMPRESS TIME",
- "DECOMPRESS TIME",
- "PARQUET RS ZSTD COMPRESS TIME",
- "PARQUET RS ZSTD DECOMPRESS TIME",
- "LANCE COMPRESS TIME",
- "LANCE DECOMPRESS TIME",
- "VORTEX:PARQUET ZSTD RATIO COMPRESS TIME",
- "VORTEX:PARQUET ZSTD RATIO DECOMPRESS TIME",
- "VORTEX:LANCE RATIO COMPRESS TIME",
- "VORTEX:LANCE RATIO DECOMPRESS TIME",
- ],
- hiddenDatasets: new Set([
- "wide table cols=1000 chunks=1 rows=1000",
- "wide table cols=1000 chunks=50 rows=1000",
- ]),
- removedDatasets: new Set([
- "TPC-H l_comment canonical",
- "TPC-H l_comment chunked without fsst",
- "wide table cols=10 chunks=1 rows=1000",
- "wide table cols=100 chunks=1 rows=1000",
- "wide table cols=10 chunks=50 rows=1000",
- "wide table cols=100 chunks=50 rows=1000",
- ]),
- renamedDatasets: { lance: "lance", Lance: "lance", LANCE: "lance" },
- },
- {
- name: "Compression Size",
- keptCharts: [
- "VORTEX SIZE",
- "PARQUET SIZE",
- "LANCE SIZE",
- "VORTEX:PARQUET ZSTD SIZE",
- "VORTEX:LANCE SIZE",
- ],
- hiddenDatasets: new Set(["wide table cols=1000"]),
- removedDatasets: new Set([
- "wide table cols=10 chunks=1 rows=1000",
- "wide table cols=100 chunks=1 rows=1000",
- "wide table cols=10 chunks=50 rows=1000",
- "wide table cols=100 chunks=50 rows=1000",
- ]),
- renamedDatasets: { lance: "lance", Lance: "lance", LANCE: "lance" },
- },
-];
-
-function querySuiteConfig(name, suite) {
- const cfg = { name, renamedDatasets: { ...ENGINE_RENAMES } };
- if (suite?.hiddenDatasets?.length)
- cfg.hiddenDatasets = new Set(suite.hiddenDatasets);
- return cfg;
-}
-
-function buildQueryConfigs() {
- const configs = [];
- for (const s of QUERY_SUITES) {
- if (s.skip) continue;
- if (!s.fanOut) {
- configs.push(querySuiteConfig(s.displayName, s));
- }
- }
- for (const g of FAN_OUT_GROUPS) {
- const suite = QUERY_SUITES.find(
- (s) => s.fanOut && g.startsWith(s.displayName),
- );
- const cfg = querySuiteConfig(g, suite);
- if (g.includes("SF=1000") || (g.includes("TPC-DS") && g.includes("SF=10)")))
- cfg.hidden = true;
- configs.push(cfg);
- }
- return configs;
-}
-
-export const BENCHMARK_CONFIGS = [...BESPOKE_CONFIGS, ...buildQueryConfigs()];
-
-// Chart name remapping (compression benchmarks only)
-export const CHART_NAME_MAP = {
- "COMPRESS TIME": "VORTEX WRITE TIME (COMPRESSION)",
- "DECOMPRESS TIME": "VORTEX SCAN TIME (DECOMPRESSION)",
- "PARQUET RS ZSTD COMPRESS TIME": "PARQUET WRITE TIME (COMPRESSION)",
- "PARQUET RS ZSTD DECOMPRESS TIME": "PARQUET SCAN TIME (DECOMPRESSION)",
- "LANCE COMPRESS TIME": "LANCE WRITE TIME (COMPRESSION)",
- "LANCE DECOMPRESS TIME": "LANCE SCAN TIME (DECOMPRESSION)",
- "VORTEX SIZE": "VORTEX SIZE",
- "PARQUET ZSTD SIZE": "PARQUET SIZE",
- "LANCE SIZE": "LANCE SIZE",
- "VORTEX:RAW SIZE": "VORTEX vs RAW SIZE RATIO",
- "VORTEX:PARQUET ZSTD SIZE": "VORTEX vs PARQUET SIZE RATIO",
- "VORTEX:LANCE SIZE": "VORTEX vs LANCE SIZE RATIO",
- "VORTEX:PARQUET ZSTD RATIO COMPRESS TIME":
- "VORTEX vs PARQUET WRITE TIME RATIO",
- "VORTEX:PARQUET ZSTD RATIO DECOMPRESS TIME":
- "VORTEX vs PARQUET SCAN TIME RATIO",
- "VORTEX:LANCE RATIO COMPRESS TIME": "VORTEX vs LANCE WRITE TIME RATIO",
- "VORTEX:LANCE RATIO DECOMPRESS TIME": "VORTEX vs LANCE SCAN TIME RATIO",
-};
-
-// Category tags for sidebar filtering
-export const CATEGORY_TAGS = {
- "Random Access": ["Read/Write"],
- Compression: ["Read/Write"],
- "Compression Size": ["Read/Write"],
-};
-for (const s of QUERY_SUITES) {
- if (!s.skip && !s.fanOut && s.tags) CATEGORY_TAGS[s.displayName] = s.tags;
-}
-for (const g of FAN_OUT_GROUPS) {
- const m = g.match(/^(.+?) \((NVMe|S3)\) \((SF=\d+)\)$/);
- CATEGORY_TAGS[g] = [
- m[2] === "S3" ? "Queries (S3)" : "Queries (NVMe)",
- `${m[1]} (${m[3]})`,
- ];
-}
-
-// Benchmark descriptions
-export const BENCHMARK_DESCRIPTIONS = {
- "Random Access":
- "Tests performance of selecting arbitrary row indices from a file on NVMe storage",
- Compression:
- "Measures encoding and decoding throughput (MB/s) for Vortex files and Parquet files (with zstd page compression)",
- "Compression Size":
- "Compares compressed file sizes and compression ratios across different encoding strategies",
-};
-for (const s of QUERY_SUITES) {
- if (s.description) BENCHMARK_DESCRIPTIONS[s.displayName] = s.description;
-}
-
-// Scale factor descriptions
-export const SCALE_FACTOR_DESCRIPTIONS = {
- 1: "SF=1 (~1GB of data)",
- 10: "SF=10 (~10GB of data)",
- 100: "SF=100 (~100GB of data)",
- 1000: "SF=1000 (~1TB of data)",
-};
-
-// Engine filter labels
-export const ENGINE_LABELS = {
- all: "All",
- duckdb: "DuckDB",
- datafusion: "DataFusion",
- vortex: "Vortex",
- parquet: "Parquet",
-};
-
-// Series color map
-export const SERIES_COLOR_MAP = {
- "vortex-nvme": "#19a508",
- "vortex-compact-nvme": "#15850a",
- "parquet-nvme": "#ef7f1d",
- "lance-nvme": "#3B82F6",
- "datafusion:arrow": "#7a27b1",
- "datafusion:in-memory-arrow": "#7a27b1",
- "datafusion:parquet": "#ef7f1d",
- "datafusion:vortex": "#19a508",
- "datafusion:vortex-compact": "#15850a",
- "datafusion:lance": "#2D936C",
- "duckdb:parquet": "#985113",
- "duckdb:vortex": "#0e5e04",
- "duckdb:vortex-compact": "#0b4a03",
- "duckdb:duckdb": "#87752e",
- "vortex:lance": "#FF8787",
-};
-
-// Fallback color palette
-export const FALLBACK_PALETTE = [
- "#5971FD",
- "#CEE562",
- "#EEB3E1",
- "#FF8C42",
- "#B8336A",
- "#726DA8",
- "#2D936C",
- "#E9B44C",
-];
-
-// Default visible commits
-export const DEFAULT_COMMIT_RANGE = 100;
diff --git a/benchmarks-website/src/main.jsx b/benchmarks-website/src/main.jsx
deleted file mode 100644
index 32fcc3f979f..00000000000
--- a/benchmarks-website/src/main.jsx
+++ /dev/null
@@ -1,10 +0,0 @@
-import React from 'react';
-import ReactDOM from 'react-dom/client';
-import App from './App';
-import './styles/index.css';
-
-ReactDOM.createRoot(document.getElementById('root')).render(
-
-
-
-);
diff --git a/benchmarks-website/src/styles/index.css b/benchmarks-website/src/styles/index.css
deleted file mode 100644
index 910670ec28f..00000000000
--- a/benchmarks-website/src/styles/index.css
+++ /dev/null
@@ -1,1319 +0,0 @@
-/* CSS Variables for consistent theming */
-:root {
- /* Vortex Brand Colors */
- --vortex-black: #101010;
- --vortex-gray: #ECECEC;
- --vortex-green: #CEE562;
- --vortex-blue: #5971FD;
- --vortex-pink: #EEB3E1;
-
- /* Theme Colors */
- --primary-color: var(--vortex-blue);
- --primary-hover: #4A5FE5;
- --accent-color: var(--vortex-green);
- --bg-color: #ffffff;
- --bg-secondary: #FAFAFA;
- --text-color: var(--vortex-black);
- --text-secondary: #666666;
- --border-color: var(--vortex-gray);
-
- /* Layout */
- --header-height: 72px;
- --sidebar-width: 280px;
- --chart-spacing: 24px;
- --mobile-breakpoint: 768px;
- --tablet-breakpoint: 1024px;
-
- /* Shadows */
- --shadow-sm: 0 1px 3px rgba(16,16,16,0.08);
- --shadow-md: 0 4px 8px rgba(16,16,16,0.08);
- --shadow-lg: 0 12px 24px rgba(16,16,16,0.12);
-
- /* Border Radius */
- --radius-sm: 4px;
- --radius-md: 8px;
- --radius-lg: 12px;
-}
-
-@media (prefers-color-scheme: dark) { :root {
- --primary-color: var(--vortex-blue);
- --primary-hover: #8a9cff;
- --accent-color: var(--vortex-green);
- --bg-color: #050507;
- --bg-secondary: #121219;
- --text-color: #F5F5F7;
- --text-secondary: #A0A0B0;
- --border-color: #30303a;
- --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.6);
- --shadow-md: 0 4px 8px rgba(0, 0, 0, 0.7);
- --shadow-lg: 0 12px 24px rgba(0, 0, 0, 0.8);
-}}
-
-/* Reset and base styles */
-* {
- box-sizing: border-box;
-}
-
-html {
- font-family: "Geist", -apple-system, BlinkMacSystemFont, "Segoe UI", "SF Pro Display", Roboto, sans-serif;
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
- background-color: var(--bg-color);
- font-size: 16px;
- scroll-behavior: smooth;
- overflow-x: hidden;
-}
-
-body {
- color: var(--text-color);
- margin: 0;
- padding: 0;
- font-size: 1em;
- font-weight: 400;
- padding-top: var(--header-height);
- line-height: 1.6;
- letter-spacing: -0.01em;
- overflow-x: hidden;
- position: relative;
-}
-
-/* Typography */
-h1, h2, h3, h4, h5, h6 {
- font-family: "Funnel Display", sans-serif;
- font-weight: 600;
- letter-spacing: -0.02em;
-}
-
-code, pre {
- font-family: "Geist Mono", monospace;
- font-size: 0.9em;
-}
-
-/* Sticky Header */
-.sticky-header {
- position: fixed;
- top: 0;
- left: 0;
- right: 0;
- height: var(--header-height);
- background: rgba(255, 255, 255, 0.95);
- -webkit-backdrop-filter: blur(10px);
- backdrop-filter: blur(10px);
- border-bottom: 1px solid var(--border-color);
- box-shadow: var(--shadow-sm);
- z-index: 1000;
- display: flex;
- align-items: center;
-}
-
-.header-content {
- display: flex;
- align-items: center;
- justify-content: space-between;
- height: 100%;
- padding: 0 32px;
- width: 100%;
- gap: 24px;
- background: var(--bg-secondary);
-}
-
-.header-left {
- display: flex;
- align-items: center;
- gap: 12px;
-}
-
-.menu-toggle {
- display: block;
- background: none;
- border: none;
- font-size: 20px;
- cursor: pointer;
- padding: 8px;
- border-radius: var(--radius-sm);
- transition: all 0.2s;
- color: var(--text-color);
-}
-
-.menu-toggle:hover {
- background-color: var(--bg-secondary);
-}
-
-.logo-link {
- display: flex;
- align-items: center;
- text-decoration: none;
- transition: opacity 0.2s;
-}
-
-.logo-link:hover {
- opacity: 0.8;
-}
-
-.site-logo {
- height: 24px;
- width: auto;
- display: block;
-}
-
-.site-title {
- font-family: "Funnel Display", sans-serif;
- font-size: 1.5rem;
- font-weight: 600;
- margin: 0;
- margin-left: calc(var(--sidebar-width) - 156px);
- color: var(--text-color);
- display: none;
- white-space: nowrap;
-}
-
-@media (min-width: 1400px) {
- .site-title {
- display: block;
- }
-}
-
-.header-center {
- flex: 1;
- display: flex;
- justify-content: center;
- padding: 0 20px;
-}
-
-.filter-controls {
- display: flex;
- align-items: center;
- gap: 16px;
- max-width: 600px;
-}
-
-.control-btn, .view-btn {
- font-family: "Geist", sans-serif;
- padding: 8px 20px;
- border: 1px solid var(--border-color);
- background: var(--bg-color);
- color: var(--text-color);
- border-radius: var(--radius-md);
- cursor: pointer;
- font-size: 14px;
- font-weight: 500;
- transition: all 0.2s;
- white-space: nowrap;
-}
-
-.control-btn:hover, .view-btn:hover {
- background-color: var(--bg-secondary);
- border-color: var(--primary-color);
- transform: translateY(-1px);
- box-shadow: var(--shadow-sm);
-}
-
-.view-btn.active {
- background-color: var(--primary-color);
- color: white;
- border-color: var(--primary-color);
-}
-
-.category-filter, .search-filter {
- font-family: "Geist", sans-serif;
- padding: 8px 12px;
- border: 1px solid var(--border-color);
- border-radius: var(--radius-md);
- font-size: 14px;
- font-weight: 500;
- background: var(--bg-color);
- color: var(--text-color);
- transition: border-color 0.2s;
-}
-
-.category-filter:focus, .search-filter:focus {
- outline: none;
- border-color: var(--primary-color);
-}
-
-.search-filter {
- width: 200px;
-}
-
-.header-right {
- display: flex;
- align-items: center;
- gap: 16px;
-}
-
-.view-controls {
- display: flex;
- gap: 4px;
-}
-
-.repo-link {
- display: flex;
- align-items: center;
- gap: 8px;
- color: var(--text-color);
- text-decoration: none;
- font-weight: 600;
- font-size: 14px;
- padding: 8px 16px;
- border: 1px solid var(--border-color);
- border-radius: var(--radius-md);
- transition: all 0.2s;
-}
-
-.github-logo {
- flex-shrink: 0;
-}
-
-.repo-link:hover {
- background-color: var(--bg-secondary);
- border-color: var(--primary-color);
- color: var(--primary-color);
-}
-
-/* Main Container */
-.main-container {
- display: flex;
- min-height: calc(100vh - var(--header-height));
- overflow-x: hidden;
- width: 100%;
-}
-
-/* Sidebar Navigation */
-.sidebar {
- width: var(--sidebar-width);
- background: var(--bg-secondary);
- -webkit-backdrop-filter: blur(10px);
- backdrop-filter: blur(10px);
- border-right: 1px solid var(--border-color);
- position: fixed;
- top: var(--header-height);
- left: 0;
- height: calc(100vh - var(--header-height));
- overflow-y: auto;
- transition: transform 0.3s ease;
- z-index: 998;
- transform: translateX(-100%);
- box-shadow: 2px 0 12px rgba(0, 0, 0, 0.15);
-}
-
-.sidebar.active,
-.sidebar.open {
- transform: translateX(0);
-}
-
-.sidebar-nav {
- display: flex;
- flex-direction: column;
- height: 100%;
-}
-
-.sidebar-header {
- padding: 20px;
- border-bottom: 1px solid var(--border-color);
- display: flex;
- justify-content: space-between;
- align-items: center;
-}
-
-.sidebar-header h2 {
- font-family: "Funnel Display", sans-serif;
- margin: 0;
- font-size: 1.2rem;
- color: var(--text-color);
- font-weight: 600;
-}
-
-.sidebar-close {
- background: none;
- border: none;
- font-size: 24px;
- cursor: pointer;
- padding: 4px;
- line-height: 1;
-}
-
-.clear-filter-btn {
- font-family: "Geist", sans-serif;
- width: calc(100% - 40px);
- margin: 16px 20px;
- padding: 10px 16px;
- background-color: var(--primary-color);
- color: white;
- border: 1px solid var(--primary-color);
- border-radius: var(--radius-md);
- font-size: 14px;
- font-weight: 500;
- cursor: pointer;
- transition: all 0.2s;
-}
-
-.clear-filter-btn:hover {
- background-color: var(--primary-hover);
- border-color: var(--primary-hover);
-}
-
-.toc-list {
- list-style: none;
- padding: 0;
- margin: 0;
- flex: 1;
- overflow-y: auto;
-}
-
-.toc-list li {
- border-bottom: 1px solid rgba(0,0,0,0.05);
-}
-
-.toc-list a {
- display: block;
- padding: 12px 20px;
- color: var(--text-color);
- text-decoration: none;
- transition: all 0.2s;
- position: relative;
-}
-
-.toc-list a:hover {
- background-color: rgba(89, 113, 253, 0.08);
- color: var(--primary-color);
- padding-left: 24px;
-}
-
-.sidebar-footer {
- padding: 20px;
- border-top: 1px solid var(--border-color);
-}
-
-.download-btn {
- display: block;
- width: 100%;
- padding: 10px 16px;
- background-color: transparent;
- color: var(--text-secondary);
- text-align: center;
- text-decoration: none;
- border: 1px solid var(--border-color);
- border-radius: var(--radius-md);
- font-size: 13px;
- font-weight: 500;
- transition: all 0.2s;
-}
-
-.download-btn:hover {
- background-color: var(--bg-secondary);
- color: var(--text-color);
- border-color: var(--text-secondary);
-}
-
-/* Sidebar overlay */
-.sidebar-overlay {
- display: none;
- position: fixed;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- background: rgba(0, 0, 0, 0.3);
- z-index: 997;
-}
-
-.sidebar-overlay.active {
- display: block;
-}
-
-/* Main Content */
-.main-content {
- flex: 1;
- padding: 32px;
- width: 100%;
- position: relative;
-}
-
-@media (min-width: 1600px) {
- .main-content {
- padding: 40px 60px;
- }
- .header-content {
- padding: 0 60px;
- }
-}
-
-@media (min-width: 1920px) {
- .main-content {
- padding: 48px 80px;
- }
- .header-content {
- padding: 0 80px;
- }
-}
-
-/* Loading Indicator */
-.loading-indicator,
-.error-indicator {
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- min-height: 400px;
- gap: 16px;
-}
-
-.loading-indicator p,
-.error-indicator p {
- font-family: "Geist", sans-serif;
- color: var(--text-secondary);
- font-size: 14px;
- font-weight: 500;
-}
-
-.spinner {
- width: 48px;
- height: 48px;
- border: 3px solid var(--border-color);
- border-top: 3px solid var(--primary-color);
- border-radius: 50%;
- animation: spin 1s linear infinite;
-}
-
-@keyframes spin {
- 0% { transform: rotate(0deg); }
- 100% { transform: rotate(360deg); }
-}
-
-/* Benchmark Sections */
-.benchmark-set {
- margin-bottom: 48px;
- background: var(--bg-color);
- border-radius: var(--radius-lg);
- border: 1px solid var(--border-color);
- overflow: visible;
- transition: opacity 0.3s ease, border-color 0.3s ease;
- position: relative;
- z-index: 1;
-}
-
-.benchmark-set:first-child {
- margin-top: 0;
-}
-
-.benchmark-set.no-data {
- opacity: 0.5;
-}
-
-.benchmark-set.no-data .benchmark-header {
- cursor: not-allowed;
-}
-
-.benchmark-set.no-data .collapse-icon {
- visibility: hidden;
-}
-
-.sticky-header-container {
- position: relative;
- z-index: 50;
- background: var(--bg-secondary);
- border-radius: var(--radius-lg) var(--radius-lg) 0 0;
- margin: 0;
- overflow: visible;
- padding: 0;
-}
-
-.benchmark-header {
- display: flex;
- align-items: center;
- gap: 12px;
- padding: 16px 32px;
- background: var(--bg-secondary);
- border-bottom: 1px solid var(--border-color);
- border-radius: var(--radius-lg);
- cursor: pointer;
- -webkit-user-select: none;
- user-select: none;
- transition: background-color 0.2s;
- overflow: visible;
-}
-
-.benchmark-header:hover {
- background: var(--bg-color);
-}
-
-.title-wrapper {
- display: flex;
- align-items: center;
- gap: 12px;
- flex: 1;
- min-width: 0;
- overflow: visible;
-}
-
-.benchmark-title {
- font-family: "Funnel Display", sans-serif;
- font-size: 1.5rem;
- font-weight: 600;
- margin: 0;
- color: var(--text-color);
- display: flex;
- align-items: center;
- gap: 12px;
- letter-spacing: -0.02em;
- line-height: 1.2;
-}
-
-.group-link-btn {
- font-size: 18px;
- background: none;
- border: none;
- cursor: pointer;
- opacity: 0.5;
- padding: 4px 8px;
- border-radius: var(--radius-sm);
- transition: opacity 0.2s, background-color 0.2s, color 0.2s;
- color: var(--text-secondary);
-}
-
-.benchmark-header:hover .group-link-btn {
- opacity: 1;
-}
-
-.group-link-btn:hover {
- background-color: var(--bg-secondary);
- color: var(--primary-color);
-}
-
-.group-link-btn.copied {
- color: var(--accent-color);
- opacity: 1;
-}
-
-.collapse-icon {
- font-size: 1rem;
- flex-shrink: 0;
- width: 1rem;
- text-align: center;
- display: inline-block;
-}
-
-.benchmark-secondary-info {
- display: flex;
- align-items: center;
- gap: 12px;
- flex-shrink: 0;
-}
-
-.benchmark-meta {
- font-family: "Geist Mono", monospace;
- display: flex;
- gap: 16px;
- font-size: 11px;
- font-weight: 500;
- color: var(--text-secondary);
- letter-spacing: 0.02em;
- text-transform: uppercase;
- flex-shrink: 0;
- line-height: 1;
-}
-
-.info-icon {
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: 20px;
- height: 20px;
- border-radius: 50%;
- background: var(--bg-secondary);
- color: var(--text-secondary);
- font-size: 16px;
- cursor: help;
- position: relative;
- transition: background-color 0.2s, color 0.2s;
- flex-shrink: 0;
-}
-
-.info-icon:hover {
- background: var(--primary-color);
- color: white;
-}
-
-.info-icon::after {
- content: attr(data-tooltip);
- position: absolute;
- bottom: calc(100% + 8px);
- left: 50%;
- transform: translateX(-50%);
- padding: 8px 12px;
- background: rgba(16, 16, 16, 0.95);
- color: white;
- font-size: 13px;
- line-height: 1.4;
- border-radius: var(--radius-sm);
- white-space: nowrap;
- opacity: 0;
- visibility: hidden;
- transition: opacity 0.2s, visibility 0.2s;
- pointer-events: none;
- z-index: 10000;
- font-weight: normal;
-}
-
-.info-icon:hover::after {
- opacity: 1;
- visibility: visible;
-}
-
-/* Generic Tooltip */
-[data-tooltip] {
- position: relative;
-}
-
-[data-tooltip]::after {
- content: attr(data-tooltip);
- position: absolute;
- bottom: 100%;
- left: 50%;
- transform: translateX(-50%);
- margin-bottom: 6px;
- padding: 6px 10px;
- background: rgba(16, 16, 16, 0.95);
- color: white;
- font-family: "Geist", sans-serif;
- font-size: 12px;
- font-weight: 500;
- line-height: 1.3;
- border-radius: var(--radius-sm);
- white-space: nowrap;
- opacity: 0;
- visibility: hidden;
- transition: all 0.15s;
- pointer-events: none;
- z-index: 1000;
-}
-
-[data-tooltip]:hover::after {
- opacity: 1;
- visibility: visible;
-}
-
-[data-tooltip]:disabled::after,
-[data-tooltip][disabled]::after {
- display: none;
-}
-
-/* Engine Filter Controls */
-.engine-filter-container {
- padding: 12px 32px;
- background: var(--bg-secondary);
- border-bottom: 1px solid var(--border-color);
- display: flex;
- align-items: center;
- gap: 12px;
- flex-wrap: wrap;
-}
-
-.engine-filter-label {
- font-family: "Geist", sans-serif;
- font-size: 14px;
- font-weight: 500;
- color: var(--text-secondary);
-}
-
-.engine-filter-btn {
- font-family: "Geist", sans-serif;
- padding: 6px 14px;
- border: 1px solid var(--border-color);
- background: var(--bg-color);
- border-radius: var(--radius-sm);
- font-size: 13px;
- font-weight: 500;
- color: var(--text-color);
- cursor: pointer;
- transition: all 0.2s;
-}
-
-.engine-filter-btn:hover {
- background-color: var(--bg-secondary);
- border-color: var(--primary-color);
-}
-
-.engine-filter-btn.active {
- background-color: var(--primary-color);
- color: white;
- border-color: var(--primary-color);
-}
-
-/* Chart Grid */
-.benchmark-graphs {
- display: grid;
- grid-template-columns: 1fr;
- gap: 20px;
- padding: 20px;
- border-radius: 0 0 var(--radius-lg) var(--radius-lg);
- background: var(--bg-color);
-}
-
-@media (min-width: 1200px) {
- .benchmark-graphs {
- grid-template-columns: repeat(2, 1fr);
- gap: 24px;
- padding: 24px;
- }
-
- .benchmark-graphs.single-chart {
- grid-template-columns: 1fr;
- max-width: 1400px;
- margin: 0 auto;
- }
-}
-
-@media (min-width: 1600px) {
- .benchmark-graphs {
- padding: 28px 32px;
- }
-}
-
-.benchmark-graphs.list-view {
- grid-template-columns: 1fr;
- max-width: 1200px;
- margin: 0 auto;
-}
-
-.chart-container {
- background: var(--bg-color);
- border: 1px solid var(--border-color);
- border-radius: var(--radius-md);
- padding: 20px;
- position: relative;
- transition: all 0.3s ease;
- display: flex;
- flex-direction: column;
-}
-
-.chart-container:hover {
- box-shadow: var(--shadow-md);
-}
-
-.chart-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 8px;
-}
-
-.chart-title {
- font-family: "Funnel Display", sans-serif;
- font-size: 16px;
- font-weight: 500;
- color: var(--text-color);
- letter-spacing: -0.01em;
- display: flex;
- align-items: center;
- gap: 8px;
-}
-
-.downsample-indicator {
- font-family: "Geist Mono", monospace;
- font-size: 10px;
- font-weight: 600;
- min-width: 100px;
- padding: 2px 6px;
- background-color: var(--vortex-pink);
- color: var(--vortex-black);
- border-radius: var(--radius-sm);
- text-transform: uppercase;
- letter-spacing: 0.02em;
-}
-
-.chart-actions {
- display: flex;
- gap: 8px;
-}
-
-.chart-action-btn {
- background: var(--bg-color);
- border: 1px solid var(--border-color);
- padding: 6px 12px;
- border-radius: var(--radius-sm);
- cursor: pointer;
- font-size: 12px;
- font-weight: 500;
- transition: all 0.2s;
- display: flex;
- align-items: center;
- gap: 6px;
-}
-
-.chart-action-btn:hover {
- background-color: #f5f5f5;
- border-color: var(--primary-color);
-}
-
-.chart-zoom-controls {
- display: flex;
- gap: 2px;
- margin-right: 8px;
-}
-
-.chart-zoom-btn {
- background: var(--bg-color);
- border: 1px solid var(--border-color);
- padding: 4px 8px;
- border-radius: var(--radius-sm);
- cursor: pointer;
- font-size: 12px;
- font-weight: 600;
- min-width: 28px;
- transition: all 0.15s;
- color: var(--text-secondary);
- display: flex;
- align-items: center;
- justify-content: center;
-}
-
-.chart-zoom-btn:hover:not(:disabled) {
- background-color: var(--primary-color);
- border-color: var(--primary-color);
- color: white;
-}
-
-.chart-zoom-btn:disabled {
- opacity: 0.4;
- cursor: not-allowed;
- background: var(--bg-secondary);
-}
-
-/* Chart Canvas */
-.chart-container canvas {
- max-height: 450px;
- min-height: 320px;
- width: 100% !important;
- height: auto !important;
- display: block;
-}
-
-.benchmark-graphs.list-view .chart-container canvas {
- max-height: 600px;
- min-height: 400px;
-}
-
-.chart-canvas-wrapper {
- position: relative;
- height: 100%;
- min-height: 320px;
-}
-
-.chart-canvas-wrapper.loading canvas {
- filter: blur(2px);
- pointer-events: none;
- transition: filter 0.2s;
-}
-
-.chart-canvas-placeholder {
- display: flex;
- align-items: center;
- justify-content: center;
- min-height: 320px;
- max-height: 450px;
- background: var(--bg-secondary);
- border-radius: var(--radius-sm);
- margin-top: 8px;
- position: relative;
- overflow: hidden;
-}
-
-.chart-loading-overlay {
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- display: flex;
- align-items: center;
- justify-content: center;
- z-index: 10;
-}
-
-.chart-loading-spinner {
- width: 32px;
- height: 32px;
- border: 3px solid var(--border-color);
- border-top-color: var(--primary-color);
- border-radius: 50%;
- animation: spin 0.8s linear infinite;
-}
-
-@keyframes spin {
- to {
- transform: rotate(360deg);
- }
-}
-
-/* Back to Top Button */
-.back-to-top {
- position: fixed;
- bottom: 32px;
- right: 32px;
- width: 48px;
- height: 48px;
- background-color: var(--primary-color);
- color: white;
- border: none;
- border-radius: 50%;
- font-size: 20px;
- cursor: pointer;
- box-shadow: 0 4px 12px rgba(89, 113, 253, 0.3);
- opacity: 0;
- visibility: hidden;
- transition: all 0.3s ease;
- z-index: 999;
-}
-
-.back-to-top.visible {
- opacity: 1;
- visibility: visible;
-}
-
-.back-to-top:hover {
- background-color: var(--primary-hover);
- transform: translateY(-4px);
- box-shadow: 0 8px 20px rgba(89, 113, 253, 0.4);
-}
-
-/* Chart Modal */
-.chart-modal {
- display: none;
- position: fixed;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- background-color: rgba(0, 0, 0, 0.8);
- z-index: 2000;
-}
-
-.chart-modal.active {
- display: flex;
- align-items: center;
- justify-content: center;
-}
-
-.modal-content {
- background: var(--bg-color);
- padding: 32px;
- border-radius: var(--radius-lg);
- width: 95%;
- max-width: 1800px;
- height: 90vh;
- position: relative;
- box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2);
-}
-
-.modal-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 16px;
-}
-
-.modal-header h2 {
- font-family: 'Funnel Display', sans-serif;
- font-size: 20px;
- font-weight: 600;
- margin: 0;
-}
-
-.modal-controls {
- display: flex;
- align-items: center;
- gap: 12px;
-}
-
-.modal-close-btn {
- background: var(--bg-color);
- border: 1px solid var(--border-color);
- padding: 6px;
- border-radius: var(--radius-sm);
- cursor: pointer;
- color: var(--text-secondary);
- display: flex;
- align-items: center;
- justify-content: center;
- transition: all 0.15s;
-}
-
-.modal-close-btn:hover {
- background-color: var(--primary-color);
- border-color: var(--primary-color);
- color: white;
-}
-
-.modal-chart-container {
- width: 100%;
- height: calc(100% - 60px);
- position: relative;
-}
-
-.modal-chart-container.loading canvas {
- filter: blur(2px);
- pointer-events: none;
- transition: filter 0.2s;
-}
-
-/* Benchmark Scores Summary */
-.benchmark-scores-summary {
- background: var(--bg-secondary);
- border-bottom: 1px solid var(--border-color);
- padding: 12px 32px;
- margin: 0;
- margin-top: 0 !important;
-}
-
-.scores-title {
- font-size: 12px;
- font-weight: 600;
- margin: 0 0 8px 0;
- color: var(--text-secondary);
- text-transform: uppercase;
- letter-spacing: 0.05em;
-}
-
-.scores-list {
- column-count: 2;
- column-gap: 20px;
-}
-
-.scores-list:has(.score-item:only-child) {
- column-count: 1;
-}
-
-@media (max-width: 780px) {
- .scores-list {
- column-count: 1;
- }
-}
-
-.score-item {
- display: flex;
- align-items: center;
- background: transparent;
- padding: 6px 0;
- margin-bottom: 4px;
- border-radius: 0;
- border: none;
- transition: none;
- font-size: 14px;
- break-inside: avoid;
-}
-
-.score-rank {
- font-weight: 500;
- color: var(--primary-color);
- min-width: 24px;
- font-size: 14px;
-}
-
-.score-series {
- flex: 1;
- font-weight: 500;
- color: var(--text-color);
- margin: 0 8px;
- font-size: 14px;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
-}
-
-.score-metrics {
- display: flex;
- gap: 6px;
- align-items: center;
-}
-
-.score-value {
- font-family: 'Geist Mono', monospace;
- font-weight: 600;
- color: var(--primary-color);
- font-size: 13px;
-}
-
-.score-runtime {
- font-family: 'Geist Mono', monospace;
- font-weight: 600;
- color: var(--text-secondary);
- background: transparent;
- padding: 0 4px;
- border-radius: 0;
- font-size: 13px;
-}
-
-.scores-explanation {
- margin-top: 8px;
- font-size: 11px;
- color: var(--text-secondary);
- font-style: italic;
- text-align: center;
-}
-
-/* Utility Classes */
-.hidden {
- display: none !important;
-}
-
-/* Mobile Styles */
-@media (max-width: 768px) {
- :root {
- --header-height: 56px;
- }
-
- .header-content {
- padding: 0 8px;
- gap: 8px;
- }
-
- .header-left {
- gap: 8px;
- }
-
- .site-logo {
- height: 16px;
- }
-
- .site-title {
- display: none;
- }
-
- .header-center {
- display: none;
- }
-
- .view-controls {
- display: none;
- }
-
- .repo-link span {
- display: none;
- }
-
- .main-content {
- padding: 16px;
- max-width: 100vw;
- }
-
- .benchmark-set {
- margin-bottom: 24px;
- border-radius: var(--radius-md);
- overflow: hidden;
- }
-
- .benchmark-header {
- padding: 12px 16px;
- flex-wrap: wrap;
- gap: 8px;
- overflow: hidden;
- }
-
- .title-wrapper {
- flex-wrap: wrap;
- gap: 8px;
- overflow: hidden;
- }
-
- .benchmark-title {
- font-size: 1.1rem;
- flex: 1 1 auto;
- min-width: 0;
- word-break: break-word;
- }
-
- .benchmark-meta {
- flex-shrink: 1;
- font-size: 10px;
- }
-
- .benchmark-secondary-info {
- flex-shrink: 1;
- min-width: 0;
- }
-
- .benchmark-graphs {
- grid-template-columns: 1fr;
- gap: 16px;
- padding: 12px;
- }
-
- .chart-container {
- padding: 12px;
- overflow: hidden;
- }
-
- .chart-header {
- flex-wrap: wrap;
- gap: 8px;
- }
-
- .chart-title {
- flex: 1 1 100%;
- min-width: 0;
- font-size: 14px;
- }
-
- .chart-actions {
- width: 100%;
- justify-content: flex-start;
- }
-
- .chart-zoom-controls {
- flex-wrap: wrap;
- gap: 4px;
- }
-
- .chart-zoom-btn {
- padding: 6px 8px;
- min-width: 32px;
- }
-
- .chart-container canvas {
- max-height: 350px;
- min-height: 250px;
- }
-
- .chart-container:hover {
- transform: none;
- box-shadow: none;
- }
-
- .chart-action-btn {
- display: none;
- }
-
- .engine-filter-container {
- padding: 12px 16px;
- flex-wrap: wrap;
- }
-
- .back-to-top {
- bottom: 16px;
- right: 16px;
- width: 40px;
- height: 40px;
- font-size: 16px;
- }
-
- .modal-content {
- padding: 16px;
- height: 90vh;
- }
-
- .modal-header {
- flex-wrap: wrap;
- gap: 8px;
- }
-
- .modal-header h2 {
- font-size: 16px;
- min-width: 0;
- word-break: break-word;
- }
-
- .benchmark-scores-summary {
- padding: 8px 16px;
- }
-}
diff --git a/benchmarks-website/src/utils.js b/benchmarks-website/src/utils.js
deleted file mode 100644
index 140ebebeb6c..00000000000
--- a/benchmarks-website/src/utils.js
+++ /dev/null
@@ -1,104 +0,0 @@
-import { SERIES_COLOR_MAP, FALLBACK_PALETTE, CHART_NAME_MAP } from './config';
-
-// Simple hash function for color selection
-function simpleHash(str) {
- let hash = 0;
- for (let i = 0; i < str.length; i++) {
- const char = str.charCodeAt(i);
- hash = ((hash << 5) - hash) + char;
- hash = hash & hash;
- }
- return Math.abs(hash);
-}
-
-export function stringToColor(str) {
- if (SERIES_COLOR_MAP[str]) {
- return SERIES_COLOR_MAP[str];
- }
-
- const lowerStr = str
- .replace(/^DataFusion:/i, 'datafusion:')
- .replace(/^DuckDB:/i, 'duckdb:')
- .replace(/^Vortex:/i, 'vortex:')
- .replace(/^Arrow:/i, 'arrow:');
-
- if (lowerStr !== str && SERIES_COLOR_MAP[lowerStr]) {
- return SERIES_COLOR_MAP[lowerStr];
- }
-
- const index = simpleHash(str) % FALLBACK_PALETTE.length;
- return FALLBACK_PALETTE[index];
-}
-
-export function remapChartName(name) {
- if (CHART_NAME_MAP[name]) {
- return CHART_NAME_MAP[name];
- }
- // Convert dashes to spaces for readability
- return name.replace(/-/g, ' ');
-}
-
-export function formatDate(timestamp) {
- if (!timestamp) return '';
- const date = new Date(timestamp);
- const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
- return `${months[date.getMonth()]} ${date.getDate()}, ${date.getFullYear()}`;
-}
-
-export function formatTime(ms) {
- if (ms < 1) return `${(ms * 1000).toFixed(0)}μs`;
- if (ms < 1000) return `${ms.toFixed(1)}ms`;
- if (ms < 60000) return `${(ms / 1000).toFixed(1)}s`;
- return `${(ms / 60000).toFixed(1)}m`;
-}
-
-export function debounce(func, wait) {
- let timeout;
- return function (...args) {
- clearTimeout(timeout);
- timeout = setTimeout(() => func.apply(this, args), wait);
- };
-}
-
-export function throttle(func, limit) {
- let inThrottle;
- return function (...args) {
- if (!inThrottle) {
- func.apply(this, args);
- inThrottle = true;
- setTimeout(() => (inThrottle = false), limit);
- }
- };
-}
-
-export function isMobile() {
- return window.innerWidth <= 768;
-}
-
-export function getBenchmarkDescription(categoryName) {
- if (categoryName.startsWith('TPC-H')) {
- const match = categoryName.match(/SF=(\d+)/);
- const sf = match ? match[1] : null;
- const sfDesc = sf ? `at SF=${sf} (~${sf === '1' ? '1GB' : sf === '10' ? '10GB' : sf === '100' ? '100GB' : '1TB'} of data)` : '';
- if (categoryName.includes('NVMe')) {
- return `TPC-H benchmark queries on local NVMe storage ${sfDesc}`;
- } else if (categoryName.includes('S3')) {
- return `TPC-H benchmark queries against S3 storage ${sfDesc}`;
- }
- }
- if (categoryName.startsWith('TPC-DS')) {
- const match = categoryName.match(/SF=(\d+)/);
- const sf = match ? match[1] : null;
- const sfDesc = sf ? `at SF=${sf}` : '';
- return `TPC-DS benchmark queries on local NVMe storage ${sfDesc}`;
- }
- const descriptions = {
- 'Random Access': 'Tests performance of selecting arbitrary row indices from a file on NVMe storage',
- 'Compression': 'Measures encoding and decoding throughput (MB/s) for Vortex and Parquet files',
- 'Compression Size': 'Compares compressed file sizes across different encoding strategies',
- 'Clickbench': "ClickHouse's analytical benchmark suite on web analytics data",
- 'Clickbench Sorted': 'ClickBench queries over data globally sorted by event date and event time',
- 'Statistical and Population Genetics': 'Statistical and population genetics queries on gnomAD dataset',
- };
- return descriptions[categoryName] || '';
-}
diff --git a/benchmarks-website/vite.config.js b/benchmarks-website/vite.config.js
deleted file mode 100644
index ad0cc7446f6..00000000000
--- a/benchmarks-website/vite.config.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import { defineConfig } from 'vite';
-import react from '@vitejs/plugin-react';
-
-export default defineConfig({
- plugins: [react()],
- publicDir: 'public',
- server: {
- port: 5173,
- proxy: {
- '/api': {
- target: 'http://localhost:3000',
- changeOrigin: true,
- },
- },
- },
- build: {
- outDir: 'dist',
- },
-});