├── .eslintrc.json
├── app
├── favicon.ico
├── components
│ ├── About
│ │ ├── SystemInfo.js
│ │ ├── ScoreExplanation.js
│ │ ├── TestProcedure.js
│ │ └── About.js
│ ├── Newsletter.js
│ ├── StickyAnnouncement.js
│ ├── DarkModeToggle.js
│ ├── Footer.js
│ ├── BrowserCard.js
│ ├── Header.js
│ └── BrowserBarChart.js
├── hooks
│ └── useLocalStorage.js
├── globals.css
├── page.js
├── lib
│ └── getBrowsers.js
├── layout.js
└── privacy
│ └── page.js
├── public
├── images
│ ├── logo.png
│ ├── BlueskyLogo.png
│ ├── browser-logos
│ │ ├── arc.png
│ │ ├── ddg.jpg
│ │ ├── dia.png
│ │ ├── neo.jpg
│ │ ├── ora.png
│ │ ├── tor.png
│ │ ├── via.png
│ │ ├── web.png
│ │ ├── brave.png
│ │ ├── chrome.png
│ │ ├── edge.png
│ │ ├── fellou.jpg
│ │ ├── floorp.png
│ │ ├── helium.jpg
│ │ ├── kito.png
│ │ ├── kiwi.png
│ │ ├── kosmik.jpg
│ │ ├── meteor.jpg
│ │ ├── mull.png
│ │ ├── nook.jpg
│ │ ├── opera.png
│ │ ├── orion.png
│ │ ├── quetta.png
│ │ ├── safari.png
│ │ ├── shift.jpg
│ │ ├── soul.png
│ │ ├── yandex.png
│ │ ├── cromite.png
│ │ ├── firefox.png
│ │ ├── ghostery.png
│ │ ├── iceraven.png
│ │ ├── mullvad.png
│ │ ├── opera-gx.png
│ │ ├── sigmaos.png
│ │ ├── thorium.webp
│ │ ├── vivaldi.png
│ │ ├── waterfox.png
│ │ ├── bravebeta.webp
│ │ ├── browseros.jpg
│ │ ├── chromebeta.png
│ │ ├── chromedev.webp
│ │ ├── deta-surf.png
│ │ ├── edge-beta.png
│ │ ├── edge-canary.png
│ │ ├── firefox-dev.png
│ │ ├── opera-beta.webp
│ │ ├── opera-mini.png
│ │ ├── strawberry.png
│ │ ├── bravenightly.webp
│ │ ├── chrome-canary.png
│ │ ├── firefox-beta.png
│ │ ├── yandex-alpha.png
│ │ ├── yandex-beta.webp
│ │ ├── zen-twilight.png
│ │ ├── firefox-nightly.png
│ │ ├── samsung-internet.png
│ │ ├── vivaldi-snapshot.png
│ │ ├── samsung-internet-beta.png
│ │ ├── zen.svg
│ │ ├── librewolf.svg
│ │ └── comet.svg
│ ├── TelegramLogo.svg
│ ├── TwitterLogo.svg
│ └── RedditLogo.svg
└── data
│ ├── raw-data.xlsx
│ ├── ipad.json
│ ├── windows.json
│ ├── browsers.json
│ ├── android.json
│ └── macos-intel.json
├── jsconfig.json
├── postcss.config.mjs
├── next.config.mjs
├── .gitignore
├── package.json
├── .github
├── FUNDING.yml
└── dependabot.yml
├── tailwind.config.js
└── README.md
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "next/core-web-vitals"
3 | }
4 |
--------------------------------------------------------------------------------
/app/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/app/favicon.ico
--------------------------------------------------------------------------------
/public/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/logo.png
--------------------------------------------------------------------------------
/public/data/raw-data.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/data/raw-data.xlsx
--------------------------------------------------------------------------------
/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "paths": {
4 | "@/*": ["./*"]
5 | }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/public/images/BlueskyLogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/BlueskyLogo.png
--------------------------------------------------------------------------------
/public/images/browser-logos/arc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/arc.png
--------------------------------------------------------------------------------
/public/images/browser-logos/ddg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/ddg.jpg
--------------------------------------------------------------------------------
/public/images/browser-logos/dia.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/dia.png
--------------------------------------------------------------------------------
/public/images/browser-logos/neo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/neo.jpg
--------------------------------------------------------------------------------
/public/images/browser-logos/ora.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/ora.png
--------------------------------------------------------------------------------
/public/images/browser-logos/tor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/tor.png
--------------------------------------------------------------------------------
/public/images/browser-logos/via.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/via.png
--------------------------------------------------------------------------------
/public/images/browser-logos/web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/web.png
--------------------------------------------------------------------------------
/public/images/browser-logos/brave.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/brave.png
--------------------------------------------------------------------------------
/public/images/browser-logos/chrome.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/chrome.png
--------------------------------------------------------------------------------
/public/images/browser-logos/edge.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/edge.png
--------------------------------------------------------------------------------
/public/images/browser-logos/fellou.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/fellou.jpg
--------------------------------------------------------------------------------
/public/images/browser-logos/floorp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/floorp.png
--------------------------------------------------------------------------------
/public/images/browser-logos/helium.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/helium.jpg
--------------------------------------------------------------------------------
/public/images/browser-logos/kito.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/kito.png
--------------------------------------------------------------------------------
/public/images/browser-logos/kiwi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/kiwi.png
--------------------------------------------------------------------------------
/public/images/browser-logos/kosmik.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/kosmik.jpg
--------------------------------------------------------------------------------
/public/images/browser-logos/meteor.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/meteor.jpg
--------------------------------------------------------------------------------
/public/images/browser-logos/mull.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/mull.png
--------------------------------------------------------------------------------
/public/images/browser-logos/nook.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/nook.jpg
--------------------------------------------------------------------------------
/public/images/browser-logos/opera.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/opera.png
--------------------------------------------------------------------------------
/public/images/browser-logos/orion.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/orion.png
--------------------------------------------------------------------------------
/public/images/browser-logos/quetta.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/quetta.png
--------------------------------------------------------------------------------
/public/images/browser-logos/safari.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/safari.png
--------------------------------------------------------------------------------
/public/images/browser-logos/shift.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/shift.jpg
--------------------------------------------------------------------------------
/public/images/browser-logos/soul.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/soul.png
--------------------------------------------------------------------------------
/public/images/browser-logos/yandex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/yandex.png
--------------------------------------------------------------------------------
/public/images/browser-logos/cromite.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/cromite.png
--------------------------------------------------------------------------------
/public/images/browser-logos/firefox.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/firefox.png
--------------------------------------------------------------------------------
/public/images/browser-logos/ghostery.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/ghostery.png
--------------------------------------------------------------------------------
/public/images/browser-logos/iceraven.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/iceraven.png
--------------------------------------------------------------------------------
/public/images/browser-logos/mullvad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/mullvad.png
--------------------------------------------------------------------------------
/public/images/browser-logos/opera-gx.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/opera-gx.png
--------------------------------------------------------------------------------
/public/images/browser-logos/sigmaos.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/sigmaos.png
--------------------------------------------------------------------------------
/public/images/browser-logos/thorium.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/thorium.webp
--------------------------------------------------------------------------------
/public/images/browser-logos/vivaldi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/vivaldi.png
--------------------------------------------------------------------------------
/public/images/browser-logos/waterfox.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/waterfox.png
--------------------------------------------------------------------------------
/public/images/browser-logos/bravebeta.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/bravebeta.webp
--------------------------------------------------------------------------------
/public/images/browser-logos/browseros.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/browseros.jpg
--------------------------------------------------------------------------------
/public/images/browser-logos/chromebeta.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/chromebeta.png
--------------------------------------------------------------------------------
/public/images/browser-logos/chromedev.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/chromedev.webp
--------------------------------------------------------------------------------
/public/images/browser-logos/deta-surf.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/deta-surf.png
--------------------------------------------------------------------------------
/public/images/browser-logos/edge-beta.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/edge-beta.png
--------------------------------------------------------------------------------
/public/images/browser-logos/edge-canary.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/edge-canary.png
--------------------------------------------------------------------------------
/public/images/browser-logos/firefox-dev.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/firefox-dev.png
--------------------------------------------------------------------------------
/public/images/browser-logos/opera-beta.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/opera-beta.webp
--------------------------------------------------------------------------------
/public/images/browser-logos/opera-mini.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/opera-mini.png
--------------------------------------------------------------------------------
/public/images/browser-logos/strawberry.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/strawberry.png
--------------------------------------------------------------------------------
/public/images/browser-logos/bravenightly.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/bravenightly.webp
--------------------------------------------------------------------------------
/public/images/browser-logos/chrome-canary.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/chrome-canary.png
--------------------------------------------------------------------------------
/public/images/browser-logos/firefox-beta.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/firefox-beta.png
--------------------------------------------------------------------------------
/public/images/browser-logos/yandex-alpha.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/yandex-alpha.png
--------------------------------------------------------------------------------
/public/images/browser-logos/yandex-beta.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/yandex-beta.webp
--------------------------------------------------------------------------------
/public/images/browser-logos/zen-twilight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/zen-twilight.png
--------------------------------------------------------------------------------
/public/images/browser-logos/firefox-nightly.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/firefox-nightly.png
--------------------------------------------------------------------------------
/public/images/browser-logos/samsung-internet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/samsung-internet.png
--------------------------------------------------------------------------------
/public/images/browser-logos/vivaldi-snapshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/vivaldi-snapshot.png
--------------------------------------------------------------------------------
/public/images/browser-logos/samsung-internet-beta.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kawaiier/browserating/HEAD/public/images/browser-logos/samsung-internet-beta.png
--------------------------------------------------------------------------------
/postcss.config.mjs:
--------------------------------------------------------------------------------
1 | /** @type {import('postcss-load-config').Config} */
2 | const config = {
3 | plugins: {
4 | tailwindcss: {},
5 | },
6 | };
7 |
8 | export default config;
9 |
--------------------------------------------------------------------------------
/next.config.mjs:
--------------------------------------------------------------------------------
1 | /** @type {import('next').NextConfig} */
2 | const nextConfig = {
3 | images: {
4 | domains: ["storage.ko-fi.com"],
5 | },
6 | };
7 |
8 | export default nextConfig;
9 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 | .yarn/install-state.gz
8 |
9 | # testing
10 | /coverage
11 |
12 | # next.js
13 | /.next/
14 | /out/
15 |
16 | # production
17 | /build
18 |
19 | # misc
20 | .DS_Store
21 | *.pem
22 |
23 | # debug
24 | npm-debug.log*
25 | yarn-debug.log*
26 | yarn-error.log*
27 |
28 | # local env files
29 | .env*.local
30 |
31 | # vercel
32 | .vercel
33 |
34 | # typescript
35 | *.tsbuildinfo
36 | next-env.d.ts
37 | .aider*
38 | .env
39 | .cursor/
40 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "browserating",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start",
9 | "lint": "next lint"
10 | },
11 | "dependencies": {
12 | "@vercel/analytics": "^1.5.0",
13 | "chart.js": "^4.4.6",
14 | "lucide-react": "^0.556.0",
15 | "next": "16.0.8",
16 | "react": "^19",
17 | "react-chartjs-2": "^5.2.0",
18 | "react-dom": "^18"
19 | },
20 | "devDependencies": {
21 | "eslint": "^9",
22 | "eslint-config-next": "16.0.8",
23 | "postcss": "^8",
24 | "tailwindcss": "^3.4.1"
25 | },
26 | "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
27 | }
28 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
4 | patreon: # Replace with a single Patreon username
5 | open_collective: # Replace with a single Open Collective username
6 | ko_fi: kawaiier
7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | liberapay: # Replace with a single Liberapay username
10 | issuehunt: # Replace with a single IssueHunt username
11 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
12 | polar: # Replace with a single Polar username
13 | buy_me_a_coffee: # Replace with a single Buy Me a Coffee username
14 | thanks_dev: # Replace with a single thanks.dev username
15 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
16 |
--------------------------------------------------------------------------------
/public/images/TelegramLogo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/app/components/About/SystemInfo.js:
--------------------------------------------------------------------------------
1 | export default function SystemInfo({ title, details }) {
2 | return (
3 |
4 |
8 | {title}
9 |
16 |
22 |
23 |
24 |
25 | {details}
26 |
27 |
28 | );
29 | }
30 |
--------------------------------------------------------------------------------
/public/images/browser-logos/zen.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # .github/dependabot.yml
2 | # -------------------------------------------------
3 | # Dependabot version‑update configuration
4 | # -------------------------------------------------
5 | version: 2
6 |
7 | updates:
8 | # 1️⃣ npm (Node.js / TypeScript) dependencies
9 | - package-ecosystem: "npm"
10 | directory: "/"
11 | schedule:
12 | interval: "daily"
13 | time: "04:00"
14 | open-pull-requests-limit: 10
15 | labels:
16 | - "dependencies"
17 | - "npm"
18 | commit-message:
19 | prefix: "chore"
20 | prefix-development: "chore"
21 | include: "scope"
22 |
23 | # 2️⃣ Docker images referenced in Dockerfiles
24 | - package-ecosystem: "docker"
25 | directory: "/"
26 | schedule:
27 | interval: "weekly"
28 | day: "wednesday"
29 | time: "03:00"
30 | open-pull-requests-limit: 5
31 | labels:
32 | - "dependencies"
33 | - "docker"
34 |
35 | # 3️⃣ GitHub Actions workflow files
36 | - package-ecosystem: "github-actions"
37 | directory: "/.github/workflows"
38 | schedule:
39 | interval: "weekly"
40 | day: "friday"
41 | time: "02:00"
42 | open-pull-requests-limit: 5
43 | labels:
44 | - "dependencies"
45 | - "github-actions"
46 |
--------------------------------------------------------------------------------
/public/images/TwitterLogo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | darkMode: "class",
4 | content: [
5 | "./pages/**/*.{js,ts,jsx,tsx,mdx}",
6 | "./components/**/*.{js,ts,jsx,tsx,mdx}",
7 | "./app/**/*.{js,ts,jsx,tsx,mdx}",
8 | ],
9 | theme: {
10 | extend: {
11 | backgroundImage: {
12 | "gradient-radial": "radial-gradient(var(--tw-gradient-stops))",
13 | "gradient-conic":
14 | "conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))",
15 | },
16 | keyframes: {
17 | "fade-out": {
18 | "0%": { opacity: "1" },
19 | "75%": { opacity: "1" },
20 | "100%": { opacity: "0" },
21 | },
22 | "bounce-gentle": {
23 | "0%, 100%": {
24 | transform: "rotate(12deg) translateY(-5%)",
25 | animationTimingFunction: "cubic-bezier(0.8, 0, 1, 1)",
26 | },
27 | "50%": {
28 | transform: "rotate(12deg) translateY(0)",
29 | animationTimingFunction: "cubic-bezier(0, 0, 0.2, 1)",
30 | },
31 | },
32 | },
33 | animation: {
34 | "fade-out": "fade-out 2s ease-out forwards",
35 | "bounce-gentle": "bounce-gentle 2s infinite",
36 | },
37 | },
38 | },
39 | plugins: [],
40 | };
41 |
--------------------------------------------------------------------------------
/app/hooks/useLocalStorage.js:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from "react";
2 |
3 | export function useLocalStorage(key, defaultValue) {
4 | // Initialize state with default value
5 | const [storedValue, setStoredValue] = useState(defaultValue);
6 | const [isLoaded, setIsLoaded] = useState(false);
7 |
8 | // Load value from localStorage on mount (client-side only)
9 | useEffect(() => {
10 | try {
11 | if (typeof window !== "undefined") {
12 | const item = window.localStorage.getItem(key);
13 | if (item) {
14 | setStoredValue(JSON.parse(item));
15 | }
16 | }
17 | } catch (error) {
18 | console.warn(`Error reading localStorage key "${key}":`, error);
19 | } finally {
20 | setIsLoaded(true);
21 | }
22 | }, [key]);
23 |
24 | // Return a wrapped version of useState's setter function that persists the new value to localStorage
25 | const setValue = (value) => {
26 | try {
27 | // Allow value to be a function so we have the same API as useState
28 | const valueToStore =
29 | value instanceof Function ? value(storedValue) : value;
30 |
31 | // Save state
32 | setStoredValue(valueToStore);
33 |
34 | // Save to localStorage (client-side only)
35 | if (typeof window !== "undefined") {
36 | window.localStorage.setItem(key, JSON.stringify(valueToStore));
37 | }
38 | } catch (error) {
39 | console.warn(`Error setting localStorage key "${key}":`, error);
40 | }
41 | };
42 |
43 | return [storedValue, setValue, isLoaded];
44 | }
45 |
--------------------------------------------------------------------------------
/app/components/About/ScoreExplanation.js:
--------------------------------------------------------------------------------
1 | export default function ScoreExplanation() {
2 | return (
3 |
4 |
5 |
6 | The higher the score, the faster the browser.
7 | {" "}
8 | Speedometer 3.1 measures browser performance by simulating user
9 | interactions on various web applications.
10 |
11 |
12 |
13 |
14 | Score Interpretation:
15 |
16 |
17 |
18 | Speedometer 3.1: Higher scores
19 | indicate faster JavaScript and DOM performance
20 |
21 |
22 | RAM Usage: Lower values
23 | indicate more efficient memory usage
24 |
25 |
26 | Adblock: Higher scores indicate
27 | better ad-blocking capabilities
28 |
29 |
30 |
31 |
32 |
33 | Note: Performance may vary based on your specific hardware, operating
34 | system version, and browser configuration.
35 |
36 |
37 | );
38 | }
39 |
--------------------------------------------------------------------------------
/app/globals.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | @keyframes fade-in {
6 | 0% {
7 | opacity: 0;
8 | transform: scale(0.95); /* Optional: Slightly scale down */
9 | }
10 | 100% {
11 | opacity: 1;
12 | transform: scale(1); /* Return to normal scale */
13 | }
14 | }
15 |
16 | .fade-in {
17 | animation: fade-in 0.4s ease-in-out forwards; /* Adjust duration and easing as needed */
18 | }
19 |
20 | @keyframes twinkle {
21 | 0%,
22 | 100% {
23 | opacity: 1;
24 | }
25 | 50% {
26 | opacity: 0.3;
27 | }
28 | }
29 |
30 | .animate-twinkle {
31 | animation: twinkle 2s ease-in-out infinite;
32 | }
33 |
34 | @keyframes bounce-gentle {
35 | 0%,
36 | 100% {
37 | transform: translateY(0);
38 | }
39 | 50% {
40 | transform: translateY(-5px);
41 | }
42 | }
43 |
44 | .animate-bounce-gentle {
45 | animation: bounce-gentle 2s ease-in-out infinite;
46 | }
47 |
48 | /* Improved focus styles for better accessibility */
49 | :focus-visible {
50 | outline: 2px solid #7853e0;
51 | outline-offset: 2px;
52 | border-radius: 0.25rem;
53 | }
54 |
55 | /* Ensure interactive elements have proper focus states */
56 | a:focus-visible,
57 | button:focus-visible,
58 | input:focus-visible,
59 | select:focus-visible,
60 | textarea:focus-visible,
61 | [tabindex]:focus-visible {
62 | outline: 2px solid #7853e0;
63 | outline-offset: 2px;
64 | box-shadow: 0 0 0 4px rgba(120, 83, 224, 0.2);
65 | }
66 |
67 | /* Dark mode focus styles */
68 | .dark a:focus-visible,
69 | .dark button:focus-visible,
70 | .dark input:focus-visible,
71 | .dark select:focus-visible,
72 | .dark textarea:focus-visible,
73 | .dark [tabindex]:focus-visible {
74 | outline-color: #9b7be8;
75 | box-shadow: 0 0 0 4px rgba(155, 123, 232, 0.2);
76 | }
77 |
--------------------------------------------------------------------------------
/public/images/RedditLogo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/page.js:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { useEffect, useState } from "react";
4 |
5 | import About from "./components/About/About";
6 | import BrowserRankingList from "./components/BrowserRankingList";
7 | import Explanation from "./components/Explanation";
8 | import Footer from "./components/Footer";
9 | import Header from "./components/Header";
10 | import Newsletter from "./components/Newsletter";
11 |
12 | export default function Home() {
13 | const [darkMode, setDarkMode] = useState(false);
14 | const [mounted, setMounted] = useState(false);
15 |
16 | useEffect(() => {
17 | // Check initial theme preference
18 | const isDarkMode =
19 | localStorage?.getItem("darkMode") === "true" ||
20 | (!("darkMode" in localStorage) &&
21 | window?.matchMedia?.("(prefers-color-scheme: dark)")?.matches);
22 |
23 | setDarkMode(isDarkMode);
24 | if (isDarkMode) {
25 | document.documentElement.classList.add("dark");
26 | }
27 | setMounted(true);
28 | }, []);
29 |
30 | const toggleDarkMode = () => {
31 | const newDarkMode = !darkMode;
32 | setDarkMode(newDarkMode);
33 | document.documentElement.classList.toggle("dark");
34 | localStorage.setItem("darkMode", newDarkMode);
35 | };
36 |
37 | // Prevent hydration mismatch by not rendering until mounted
38 | if (!mounted) {
39 | return null;
40 | }
41 |
42 | return (
43 |
59 | );
60 | }
61 |
--------------------------------------------------------------------------------
/app/components/Newsletter.js:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from "react";
2 |
3 | export default function Newsletter() {
4 | const [subscriberCount, setSubscriberCount] = useState(7); // Dynamic count
5 |
6 | // Simulate growing subscriber count
7 | useEffect(() => {
8 | const interval = setInterval(() => {
9 | setSubscriberCount((prev) => prev + Math.floor(Math.random() * 3));
10 | }, 30000); // Update every 30 seconds
11 | return () => clearInterval(interval);
12 | }, []);
13 |
14 | return (
15 |
16 | {/* Background pattern */}
17 |
18 |
19 |
20 |
32 |
33 |
34 |
35 |
36 | ⚠️{" "}
37 |
38 | Subscribed before Aug 24, 2025? Please re-subscribe due to
39 | technical issues. Sorry for the inconvenience!
40 |
41 |
42 |
43 |
44 | 🔒 No spam, ever. Unsubscribe with one click.
45 |
46 |
47 | Free forever • Monthly updates • Browser insights
48 |
49 |
50 |
51 |
52 |
53 | );
54 | }
55 |
--------------------------------------------------------------------------------
/app/lib/getBrowsers.js:
--------------------------------------------------------------------------------
1 | export async function getBrowsers() {
2 | const [
3 | browsersResponse,
4 | androidResponse,
5 | macosIntelResponse,
6 | macosArmResponse,
7 | windowsResponse,
8 | ipadResponse,
9 | ] = await Promise.all([
10 | fetch("/data/browsers.json"),
11 | fetch("/data/android.json"),
12 | fetch("/data/macos-intel.json"),
13 | fetch("/data/macos-arm.json"),
14 | fetch("/data/windows.json"),
15 | fetch("/data/ipad.json"),
16 | ]);
17 |
18 | if (
19 | !browsersResponse.ok ||
20 | !androidResponse.ok ||
21 | !macosIntelResponse.ok ||
22 | !macosArmResponse.ok ||
23 | !windowsResponse.ok ||
24 | !ipadResponse.ok
25 | ) {
26 | throw new Error("Failed to fetch browser data");
27 | }
28 |
29 | const [
30 | browsers,
31 | androidData,
32 | macosIntelData,
33 | macosArmData,
34 | windowsData,
35 | ipadData,
36 | ] = await Promise.all([
37 | browsersResponse.json(),
38 | androidResponse.json(),
39 | macosIntelResponse.json(),
40 | macosArmResponse.json(),
41 | windowsResponse.json(),
42 | ipadResponse.json(),
43 | ]);
44 |
45 | // Merge the data from all sources
46 | return browsers.map((browser) => {
47 | const androidBrowser = androidData.find((b) => b.name === browser.name);
48 | const macosIntelBrowser = macosIntelData.find(
49 | (b) => b.name === browser.name
50 | );
51 | const macosArmBrowser = macosArmData.find((b) => b.name === browser.name);
52 | const windowsBrowser = windowsData.find((b) => b.name === browser.name);
53 | const ipadBrowser = ipadData.find((b) => b.name === browser.name);
54 |
55 | return {
56 | ...browser,
57 | android: androidBrowser
58 | ? { versions: androidBrowser.versions, engine: androidBrowser.engine }
59 | : null,
60 | "macos-intel": macosIntelBrowser
61 | ? {
62 | versions: macosIntelBrowser.versions,
63 | engine: macosIntelBrowser.engine,
64 | }
65 | : null,
66 | "macos-arm": macosArmBrowser
67 | ? { versions: macosArmBrowser.versions, engine: macosArmBrowser.engine }
68 | : null,
69 | windows: windowsBrowser
70 | ? { versions: windowsBrowser.versions, engine: windowsBrowser.engine }
71 | : null,
72 | ipad: ipadBrowser
73 | ? { versions: ipadBrowser.versions, engine: ipadBrowser.engine }
74 | : null,
75 | };
76 | });
77 | }
78 |
--------------------------------------------------------------------------------
/public/data/ipad.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "name": "Arc Browser",
4 | "engine": "WebKit",
5 | "versions": [
6 | {
7 | "version": "1.43.0",
8 | "scores": {
9 | "speedometer3": 27.2
10 | }
11 | }
12 | ]
13 | },
14 | {
15 | "name": "Brave",
16 | "engine": "WebKit",
17 | "versions": [
18 | {
19 | "version": "1.78.1",
20 | "scores": {
21 | "speedometer3": 21.83
22 | }
23 | }
24 | ]
25 | },
26 | {
27 | "name": "Google Chrome",
28 | "engine": "WebKit",
29 | "versions": [
30 | {
31 | "version": "137.0.7151.34",
32 | "scores": {
33 | "speedometer3": 22.27
34 | }
35 | }
36 | ]
37 | },
38 | {
39 | "name": "DuckDuckGo",
40 | "engine": "WebKit",
41 | "versions": [
42 | {
43 | "version": "7.169.0",
44 | "scores": {
45 | "speedometer3": 25.07
46 | }
47 | }
48 | ]
49 | },
50 | {
51 | "name": "Firefox",
52 | "engine": "WebKit",
53 | "versions": [
54 | {
55 | "version": "138.2",
56 | "scores": {
57 | "speedometer3": 27.87
58 | }
59 | }
60 | ]
61 | },
62 | {
63 | "name": "Microsoft Edge",
64 | "engine": "WebKit",
65 | "versions": [
66 | {
67 | "version": "136.3240.77",
68 | "scores": {
69 | "speedometer3": 23.23
70 | }
71 | }
72 | ]
73 | },
74 | {
75 | "name": "Opera",
76 | "engine": "WebKit",
77 | "versions": [
78 | {
79 | "version": "5.5.3",
80 | "scores": {
81 | "speedometer3": 27.17
82 | }
83 | }
84 | ]
85 | },
86 | {
87 | "name": "Orion",
88 | "engine": "WebKit",
89 | "versions": [
90 | {
91 | "version": "1.3.23",
92 | "scores": {
93 | "speedometer3": 26.1
94 | }
95 | }
96 | ]
97 | },
98 | {
99 | "name": "Safari",
100 | "engine": "WebKit",
101 | "versions": [
102 | {
103 | "version": "18.5",
104 | "scores": {
105 | "speedometer3": 30.9
106 | }
107 | }
108 | ]
109 | },
110 | {
111 | "name": "Vivaldi",
112 | "engine": "WebKit",
113 | "versions": [
114 | {
115 | "version": "7.4.3691.46",
116 | "scores": {
117 | "speedometer3": 19.3
118 | }
119 | }
120 | ]
121 | }
122 | ]
123 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Browserating
2 |
3 | Browserating is a Next.js web application that provides performance rankings and comparisons for macOS browsers. It uses data from Speedometer 3.1 benchmarks to give users a comprehensive view of browser performance.
4 |
5 | ## Features
6 |
7 | - Responsive design for optimal viewing on various devices
8 | - Display a ranking list of macOS browsers based on performance metrics
9 | - Filter browsers based on their engine
10 | - Detailed information for each browser, including multiple versions
11 | - Privacy-focused with dedicated privacy page
12 |
13 | ## Technologies Used
14 |
15 | - Next.js 14.2.6 (App Router)
16 | - React 18
17 | - Tailwind CSS 3.4.1
18 | - Chart.js 4.4.6 with react-chartjs-2
19 | - Lucide React for icons
20 | - Vercel Analytics
21 | - JSON for data storage
22 |
23 | ## Setup and Installation
24 |
25 | 1. Clone the repository:
26 |
27 | ```
28 | git clone https://github.com/kawaiier/browserating.git
29 | cd browserating
30 | ```
31 |
32 | 2. Install dependencies:
33 |
34 | ```
35 | npm install
36 | ```
37 |
38 | 3. Run the development server:
39 |
40 | ```
41 | npm run dev
42 | ```
43 |
44 | 4. Open [http://localhost:3000](http://localhost:3000) in your browser to see the application.
45 |
46 | ## Data Management
47 |
48 | Browser data is stored in `public/data/`. To update browser information:
49 |
50 | 1. Open `platform.json` in a text editor
51 | 2. Modify the JSON data following the existing structure
52 | 3. Save the file
53 |
54 | The application will automatically reflect the changes on the next load.
55 |
56 | ## Contributing
57 |
58 | Contributions are welcome! Please feel free to submit a Pull Request.
59 |
60 | ## Acknowledgments
61 |
62 | - Speedometer 3.1 for providing benchmark data - https://browserbench.org/Speedometer3.1/
63 | - Creator of AdBlock Tester - https://adblock-tester.com/
64 | - All browser developers for their continuous work on improving web technologies
65 |
66 | ## Say Thanks
67 |
68 | If you find this project useful, please consider supporting me with a coffee.
69 |
70 | [](https://ko-fi.com/J3J8TMWMG)
71 |
72 | ### Donation Addresses
73 |
74 | - **BTC**: `bc1qfyad27catyr8rtdhhydn8ummf996kxtesuw4hr`
75 | - **XMR**: `41zM5Hk39icMLDnbAckLpJHMwMPQKAQEADYA1AvjoZw9Y9NC7atnubrWPZKXWRbpZeGg66DkstQmA1oPZurRBcvRFbQ3PLs`
76 | - **LTC**: `ltc1qnqldulnxsxpz4g89uklsepjeqx7cajynzyr7tc`
77 | - **MATIC**: `0x6c056E9ccB183c08e9248eAF26160B5793221513`
78 |
79 | ## Star History
80 |
81 | [](https://star-history.com/#kawaiier/browserating&Date)
82 |
--------------------------------------------------------------------------------
/app/components/StickyAnnouncement.js:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import React, { useEffect, useState } from "react";
4 |
5 | const StickyAnnouncement = () => {
6 | const [isVisible, setIsVisible] = useState(true);
7 | const [currentAnnouncement, setCurrentAnnouncement] = useState(null);
8 |
9 | // Define three different announcements
10 | const announcements = [
11 | {
12 | id: 1,
13 | content: (
14 |
15 | Subscribe to /r/aiBrowsing — A
16 | place for discussing browsers and extensions that incorporate AI
17 | features
18 |
19 | ),
20 | buttonText: "Subscribe",
21 | buttonUrl: "https://www.reddit.com/r/aiBrowsing/",
22 | gradient: "from-orange-500 to-red-500",
23 | buttonClass: "bg-orange-600 hover:bg-orange-700 text-white",
24 | },
25 | {
26 | id: 2,
27 | content: (
28 |
29 | Follow me on X for the latest
30 | updates and more
31 |
32 | ),
33 | buttonText: "Follow",
34 | buttonUrl: "https://x.com/kawaiier101",
35 | gradient: "from-black to-blue-500",
36 | buttonClass: "bg-black hover:bg-blue-700 text-white",
37 | },
38 | {
39 | id: 3,
40 | content: (
41 |
42 | Join our Telegram community to
43 | discuss browsers and extensions
44 |
45 | ),
46 | buttonText: "Join",
47 | buttonUrl: "https://t.me/thebrowsershq",
48 | gradient: "from-blue-400 to-cyan-400",
49 | buttonClass: "bg-blue-500 hover:bg-cyan-500 text-white",
50 | },
51 | ];
52 |
53 | // Select a random announcement on component mount
54 | useEffect(() => {
55 | const randomIndex = Math.floor(Math.random() * announcements.length);
56 | setCurrentAnnouncement(announcements[randomIndex]);
57 | }, []);
58 |
59 | if (!isVisible || !currentAnnouncement) {
60 | return null;
61 | }
62 |
63 | return (
64 |
67 | {currentAnnouncement.content}
68 |
69 |
83 | {currentAnnouncement.buttonText}
84 |
85 |
setIsVisible(false)}
87 | className="text-white hover:text-gray-200 text-xl font-bold leading-none flex items-center justify-center h-6 w-6 rounded-full focus:outline-none focus:ring-2 focus:ring-white focus:ring-opacity-50"
88 | aria-label="Dismiss announcement"
89 | >
90 | ×
91 |
92 |
93 |
94 | );
95 | };
96 |
97 | export default StickyAnnouncement;
98 |
--------------------------------------------------------------------------------
/app/components/DarkModeToggle.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | export default function DarkModeToggle({ darkMode, toggleDarkMode }) {
4 | // Pre-calculate star positions to avoid repositioning on every render
5 | const stars = Array.from({ length: 6 }).map((_, i) => ({
6 | top: Math.random() * 100,
7 | left: Math.random() * 100,
8 | delay: Math.random() * 1500,
9 | key: `star-${i}`,
10 | }));
11 |
12 | return (
13 |
24 |
25 | {/* Sun */}
26 |
31 | {/* Main sun circle */}
32 |
33 |
34 | {/* Sun rays */}
35 | {[...Array(12)].map((_, i) => (
36 |
45 | ))}
46 |
47 |
48 | {/* Moon */}
49 |
54 | {/* Main moon circle */}
55 |
56 |
57 | {/* Moon craters */}
58 |
59 |
60 |
61 |
62 |
63 | {/* Stars (visible in dark mode) */}
64 |
70 | {stars.map((star) => (
71 |
80 | ))}
81 |
82 |
83 |
84 | );
85 | }
86 |
--------------------------------------------------------------------------------
/app/layout.js:
--------------------------------------------------------------------------------
1 | import "./globals.css";
2 |
3 | import { Analytics } from "@vercel/analytics/next";
4 | import { Inter } from "next/font/google";
5 | import Script from "next/script";
6 | import StickyAnnouncement from "./components/StickyAnnouncement";
7 |
8 | const inter = Inter({ subsets: ["latin"] });
9 |
10 | export const metadata = {
11 | title: "BrowseRating - Browser Performance for macOS, Windows and Android",
12 | description:
13 | "Compare performance of macOS, Windows and Android browsers based on Speedometer 3 benchmark results, adblocking quality, and RAM usage. Find the fastest and most efficient browsers for your device.",
14 | keywords:
15 | "browser performance, browser benchmark, Speedometer 3, browser comparison, fastest browser, macOS browser, Windows browser, Android browser, adblocking quality, RAM usage",
16 | authors: [{ name: "Sergei Manvelov" }],
17 | openGraph: {
18 | title: "BrowseRating - Browser Performance Comparison",
19 | description:
20 | "Compare browser performance across macOS, Windows and Android based on Speedometer 3 benchmark results, adblocking quality, and RAM usage.",
21 | url: "https://browserating.com",
22 | siteName: "BrowseRating",
23 | locale: "en_US",
24 | type: "website",
25 | },
26 | twitter: {
27 | card: "summary_large_image",
28 | title: "BrowseRating - Browser Performance Comparison",
29 | description:
30 | "Compare browser performance across macOS, Windows and Android based on Speedometer 3 benchmark results, adblocking quality, and RAM usage.",
31 | creator: "@kawaiier101",
32 | },
33 | robots: {
34 | index: true,
35 | follow: true,
36 | },
37 | };
38 |
39 | export default function RootLayout({ children }) {
40 | return (
41 |
42 |
43 |
44 |
45 |
46 |
57 |
74 |
75 |
76 | {children}
77 |
78 |
79 |
85 |
86 |
87 | );
88 | }
89 |
--------------------------------------------------------------------------------
/app/components/About/TestProcedure.js:
--------------------------------------------------------------------------------
1 | export default function TestProcedure() {
2 | return (
3 |
4 |
5 |
18 |
19 | For Speedometer benchmark, for each browser{" "}
20 |
21 | five tests were conducted
22 |
23 | . The{" "}
24 |
25 | best and worst results were eliminated
26 |
27 | , and the{" "}
28 |
29 | average of the remaining three tests was calculated
30 | {" "}
31 | to determine the final result.
32 |
33 |
34 |
35 |
36 |
49 |
50 | For RAM usage test,{" "}
51 |
52 | the cumulative memory consumption was measured
53 | {" "}
54 | after sequentially loading seven diverse websites: IGN, ESPN, Figma,
55 | Britannica, Wired, Bloomberg, and Reddit's popular page.
56 | Measurements were taken using Activity Monitor, filtered by each
57 | browser's name.
58 |
59 |
60 |
61 |
89 |
90 | );
91 | }
92 |
--------------------------------------------------------------------------------
/public/images/browser-logos/librewolf.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
19 |
21 |
45 |
47 |
48 |
50 | image/svg+xml
51 |
53 |
54 |
55 |
56 |
57 |
62 |
68 |
73 |
89 |
90 |
91 |
--------------------------------------------------------------------------------
/public/data/windows.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "name": "Arc Browser",
4 | "engine": "Blink",
5 | "versions": [
6 | {
7 | "version": "1.68.0",
8 | "scores": {
9 | "speedometer3": 21.92
10 | }
11 | },
12 | {
13 | "version": "1.59.0",
14 | "scores": {
15 | "speedometer3": 17.23
16 | }
17 | }
18 | ]
19 | },
20 | {
21 | "name": "Brave",
22 | "engine": "Blink",
23 | "versions": [
24 | {
25 | "version": "1.81.136",
26 | "scores": {
27 | "speedometer3": 21.02
28 | }
29 | },
30 | {
31 | "version": "1.69.162",
32 | "scores": {
33 | "speedometer3": 16.83
34 | }
35 | }
36 | ]
37 | },
38 | {
39 | "name": "DuckDuckGo Browser",
40 | "engine": "Blink",
41 | "versions": [
42 | {
43 | "version": "0.125.3",
44 | "scores": {
45 | "speedometer3": 17.77
46 | }
47 | },
48 | {
49 | "version": "0.105.0",
50 | "scores": {
51 | "speedometer3": 17.07
52 | }
53 | }
54 | ]
55 | },
56 | {
57 | "name": "Firefox",
58 | "engine": "Gecko",
59 | "versions": [
60 | {
61 | "version": "142.0",
62 | "scores": {
63 | "speedometer3": 17.83
64 | }
65 | },
66 | {
67 | "version": "130.0",
68 | "scores": {
69 | "speedometer3": 16.33
70 | }
71 | }
72 | ]
73 | },
74 | {
75 | "name": "Firefox Developer Edition",
76 | "engine": "Gecko",
77 | "versions": [
78 | {
79 | "version": "143.0b4",
80 | "scores": {
81 | "speedometer3": 17.63
82 | }
83 | },
84 | {
85 | "version": "131.0b4",
86 | "scores": {
87 | "speedometer3": 16.13
88 | }
89 | }
90 | ]
91 | },
92 | {
93 | "name": "Firefox Nightly",
94 | "engine": "Gecko",
95 | "versions": [
96 | {
97 | "version": "144.0a1",
98 | "scores": {
99 | "speedometer3": 17.73
100 | }
101 | },
102 | {
103 | "version": "132.0a1",
104 | "scores": {
105 | "speedometer3": 15.97
106 | }
107 | }
108 | ]
109 | },
110 | {
111 | "name": "Floorp",
112 | "engine": "Gecko",
113 | "versions": [
114 | {
115 | "version": "11.18.1",
116 | "scores": {
117 | "speedometer3": 15.56
118 | }
119 | }
120 | ]
121 | },
122 | {
123 | "name": "Google Chrome",
124 | "engine": "Blink",
125 | "versions": [
126 | {
127 | "version": "139.0.7258.139",
128 | "scores": {
129 | "speedometer3": 23.25
130 | }
131 | },
132 | {
133 | "version": "128.0.6613.121",
134 | "scores": {
135 | "speedometer3": 18.57
136 | }
137 | }
138 | ]
139 | },
140 | {
141 | "name": "Google Chrome Canary",
142 | "engine": "Blink",
143 | "versions": [
144 | {
145 | "version": "141.0.7376.0",
146 | "scores": {
147 | "speedometer3": 22.52
148 | }
149 | },
150 | {
151 | "version": "130.0.6710.0",
152 | "scores": {
153 | "speedometer3": 18.03
154 | }
155 | }
156 | ]
157 | },
158 | {
159 | "name": "Microsoft Edge",
160 | "engine": "Blink",
161 | "versions": [
162 | {
163 | "version": "139.0.3405.111",
164 | "scores": {
165 | "speedometer3": 23.91
166 | }
167 | },
168 | {
169 | "version": "128.0.2739.67",
170 | "scores": {
171 | "speedometer3": 17.4
172 | }
173 | }
174 | ]
175 | },
176 | {
177 | "name": "Opera",
178 | "engine": "Blink",
179 | "versions": [
180 | {
181 | "version": "120.0.5543.201",
182 | "scores": {
183 | "speedometer3": 21.17
184 | }
185 | },
186 | {
187 | "version": "113.0.5230.86",
188 | "scores": {
189 | "speedometer3": 17.8
190 | }
191 | }
192 | ]
193 | },
194 | {
195 | "name": "Opera GX",
196 | "engine": "Blink",
197 | "versions": [
198 | {
199 | "version": "120.0.5543.204",
200 | "scores": {
201 | "speedometer3": 21.2
202 | }
203 | },
204 | {
205 | "version": "113.0.5230.75",
206 | "scores": {
207 | "speedometer3": 17.53
208 | }
209 | }
210 | ]
211 | },
212 | {
213 | "name": "Vivaldi",
214 | "engine": "Blink",
215 | "versions": [
216 | {
217 | "version": "7.5.3735.64",
218 | "scores": {
219 | "speedometer3": 21.7
220 | }
221 | },
222 | {
223 | "version": "6.9.3447.44",
224 | "scores": {
225 | "speedometer3": 17.87
226 | }
227 | }
228 | ]
229 | },
230 | {
231 | "name": "Waterfox",
232 | "engine": "Gecko",
233 | "versions": [
234 | {
235 | "version": "6.5.11",
236 | "scores": {
237 | "speedometer3": 15.23
238 | }
239 | },
240 | {
241 | "version": "6.0.19",
242 | "scores": {
243 | "speedometer3": 10.2
244 | }
245 | }
246 | ]
247 | },
248 | {
249 | "name": "Yandex Browser",
250 | "engine": "Blink",
251 | "versions": [
252 | {
253 | "version": "25.8.0.1872",
254 | "scores": {
255 | "speedometer3": 21.85
256 | }
257 | },
258 | {
259 | "version": "24.7.1.1144",
260 | "scores": {
261 | "speedometer3": 17.6
262 | }
263 | }
264 | ]
265 | },
266 | {
267 | "name": "Zen Browser",
268 | "engine": "Gecko",
269 | "versions": [
270 | {
271 | "version": "1.14.11b",
272 | "scores": {
273 | "speedometer3": 17.08
274 | }
275 | }
276 | ]
277 | },
278 | {
279 | "name": "Zen Browser Twilight",
280 | "engine": "Gecko",
281 | "versions": [
282 | {
283 | "version": "1.15t (2025-08-25)",
284 | "scores": {
285 | "speedometer3": 16.77
286 | }
287 | },
288 | {
289 | "version": "1.0.0-a39",
290 | "scores": {
291 | "speedometer3": 14.83
292 | }
293 | },
294 | {
295 | "version": "1.0.0-a28",
296 | "scores": {
297 | "speedometer3": 11.5
298 | }
299 | }
300 | ]
301 | }
302 | ]
303 |
--------------------------------------------------------------------------------
/public/images/browser-logos/comet.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/app/privacy/page.js:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import Footer from "../components/Footer";
4 | import Image from "next/image";
5 | import Link from "next/link";
6 | import React from "react";
7 |
8 | export default function PrivacyPage() {
9 | return (
10 | <>
11 |
28 |
29 |
30 |
31 | Privacy Policy
32 |
33 | Last updated: March 9, 2025
34 |
35 |
36 | Introduction
37 |
38 | This Privacy Policy explains how we collect, use, and protect your
39 | information when you use our website. We are committed to ensuring
40 | the privacy and security of your data while providing you with a
41 | transparent understanding of our practices.
42 |
43 |
44 |
45 | Information We Collect
46 |
47 |
48 |
49 | Newsletter Subscription
50 |
51 |
52 |
53 | We collect email addresses when you voluntarily subscribe to our
54 | newsletter through Beehive.
55 |
56 |
57 | Your email address is used solely for sending you our newsletter
58 | and related communications.
59 |
60 |
61 | You can unsubscribe from our newsletter at any time by using the
62 | unsubscribe link provided in each email.
63 |
64 |
65 |
66 |
67 | Anonymous Usage Statistics
68 |
69 |
70 | We use Counter.dev and Vercel Analytics to collect anonymous
71 | statistical information about website visits, including:
72 |
73 |
74 | Day and time of visits
75 | Device type (Phone, Tablet, or Computer)
76 | Referral source (which website the visit came from)
77 | Browser type
78 | Country (based on IP address)
79 | Operating system
80 | Screen size
81 | Preferred language
82 | Pages visited
83 | Web vitals metrics (page load time, interaction times)
84 | Route changes
85 |
86 | This data is:
87 |
88 | Collected anonymously
89 |
90 | Aggregated on hourly, daily, weekly, monthly, and yearly basis
91 |
92 |
93 | Partially deleted after certain time periods to enhance privacy
94 |
95 | Never used to personally identify individual users
96 |
97 |
98 | Technical Services
99 |
100 | We use Bunny.net as our CDN provider, which may process technical
101 | information necessary for delivering our website content efficiently
102 | and securely.
103 |
104 |
105 |
106 | How We Use Your Information
107 |
108 |
109 |
110 | Email addresses are used exclusively for:
111 |
112 | Sending newsletters you've subscribed to
113 | Communicating important website updates when necessary
114 |
115 |
116 |
117 | Anonymous usage statistics are used for:
118 |
119 | Understanding how our website is used
120 | Improving user experience
121 | Analyzing website performance
122 |
123 |
124 |
125 |
126 |
127 | Data Sharing and Third Parties
128 |
129 |
130 | We do not sell, trade, or otherwise transfer your information to
131 | third parties. We only work with the following service providers who
132 | help us operate our website:
133 |
134 |
135 | Bunny.net (CDN services)
136 | Beehive (newsletter management)
137 | Counter.dev (anonymous analytics)
138 |
139 | Vercel Analytics (anonymous performance and usage analytics)
140 |
141 |
142 |
143 | Data Security
144 |
145 | We implement appropriate security measures to protect your
146 | information. Your email address is stored securely through our
147 | newsletter service provider.
148 |
149 |
150 | Your Rights
151 |
152 |
153 | You have the right to unsubscribe from our newsletter at any time.
154 |
155 | Request information about what data we hold about you.
156 |
157 | Request deletion of your email address from our newsletter
158 | database.
159 |
160 |
161 |
162 | Contact Us
163 |
164 | If you have any questions about this Privacy Policy or our data
165 | practices, please contact us at kawaiier@tutanota.com.
166 |
167 |
168 |
169 | Changes to This Policy
170 |
171 |
172 | We may update this Privacy Policy from time to time. We will notify
173 | you of any changes by posting the new Privacy Policy on this page
174 | and updating the 'Last updated' date.
175 |
176 |
177 |
178 |
179 | >
180 | );
181 | }
182 |
--------------------------------------------------------------------------------
/public/data/browsers.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "name": "Floorp",
4 | "logo": "/images/browser-logos/floorp.png",
5 | "website": "https://floorp.app/en"
6 | },
7 | {
8 | "name": "Mullvad Browser",
9 | "logo": "/images/browser-logos/mullvad.png",
10 | "website": "https://mullvad.net/en/browser"
11 | },
12 | {
13 | "name": "Librewolf",
14 | "logo": "/images/browser-logos/librewolf.svg",
15 | "website": "https://librewolf.net/"
16 | },
17 | {
18 | "name": "Firefox",
19 | "logo": "/images/browser-logos/firefox.png",
20 | "website": "https://www.mozilla.org/firefox/"
21 | },
22 | {
23 | "name": "Firefox Developer Edition",
24 | "engine": "Gecko",
25 | "logo": "/images/browser-logos/firefox-dev.png",
26 | "website": "https://www.mozilla.org/en-US/firefox/developer/"
27 | },
28 | {
29 | "name": "Firefox Beta",
30 | "logo": "/images/browser-logos/firefox-beta.png",
31 | "website": "https://www.mozilla.org/en-US/firefox/channel/desktop/#beta"
32 | },
33 | {
34 | "name": "Firefox Nightly",
35 | "logo": "/images/browser-logos/firefox-nightly.png",
36 | "website": "https://www.mozilla.org/en-US/firefox/channel/desktop/#nightly"
37 | },
38 | {
39 | "name": "Waterfox",
40 | "logo": "/images/browser-logos/waterfox.png",
41 | "website": "https://www.waterfox.net/"
42 | },
43 | {
44 | "name": "Zen Browser",
45 | "logo": "/images/browser-logos/zen.svg",
46 | "website": "https://www.zen-browser.app/"
47 | },
48 | {
49 | "name": "Zen Browser Twilight",
50 | "logo": "/images/browser-logos/zen-twilight.png",
51 | "website": "https://zen-browser.app/download/?twilight"
52 | },
53 | {
54 | "name": "Tor Browser",
55 | "logo": "/images/browser-logos/tor.png",
56 | "website": "https://www.torproject.org/download/"
57 | },
58 | {
59 | "name": "Brave",
60 | "logo": "/images/browser-logos/brave.png",
61 | "website": "https://brave.com/"
62 | },
63 | {
64 | "name": "Brave Beta",
65 | "logo": "/images/browser-logos/bravebeta.webp",
66 | "website": "https://brave.com/"
67 | },
68 | {
69 | "name": "Brave Nightly",
70 | "logo": "/images/browser-logos/bravenightly.webp",
71 | "website": "https://brave.com/"
72 | },
73 | {
74 | "name": "Google Chrome",
75 | "logo": "/images/browser-logos/chrome.png",
76 | "website": "https://www.google.com/chrome/"
77 | },
78 | {
79 | "name": "Google Chrome Canary",
80 | "logo": "/images/browser-logos/chrome-canary.png",
81 | "website": "https://www.google.com/chrome/canary/"
82 | },
83 | {
84 | "name": "Google Chrome Beta",
85 | "logo": "/images/browser-logos/chromebeta.png",
86 | "website": "https://www.google.com/chrome/beta/"
87 | },
88 | {
89 | "name": "Samsung Internet",
90 | "logo": "/images/browser-logos/samsung-internet.png",
91 | "website": "https://www.samsung.com/us/support/owners/app/samsung-internet"
92 | },
93 | {
94 | "name": "Samsung Internet Beta",
95 | "logo": "/images/browser-logos/samsung-internet-beta.png",
96 | "website": "https://www.samsung.com/us/support/owners/app/samsung-internet"
97 | },
98 | {
99 | "name": "Orion",
100 | "logo": "/images/browser-logos/orion.png",
101 | "website": "https://kagi.com/orion/"
102 | },
103 | {
104 | "name": "Safari",
105 | "logo": "/images/browser-logos/safari.png",
106 | "website": "https://www.apple.com/safari/"
107 | },
108 | {
109 | "name": "DuckDuckGo Browser",
110 | "logo": "/images/browser-logos/ddg.jpg",
111 | "website": "https://duckduckgo.com/"
112 | },
113 | {
114 | "name": "Microsoft Edge",
115 | "logo": "/images/browser-logos/edge.png",
116 | "website": "https://www.microsoft.com/edge"
117 | },
118 | {
119 | "name": "Microsoft Edge Beta",
120 | "logo": "/images/browser-logos/edge-beta.png",
121 | "website": "https://www.microsoft.com/edge"
122 | },
123 | {
124 | "name": "Microsoft Edge Canary",
125 | "logo": "/images/browser-logos/edge-canary.png",
126 | "website": "https://www.microsoft.com/edge"
127 | },
128 | {
129 | "name": "Opera",
130 | "logo": "/images/browser-logos/opera.png",
131 | "website": "https://www.opera.com/"
132 | },
133 | {
134 | "name": "Opera Beta",
135 | "logo": "/images/browser-logos/opera-beta.webp",
136 | "website": "https://www.opera.com/"
137 | },
138 | {
139 | "name": "Opera Mini",
140 | "logo": "/images/browser-logos/opera-mini.png",
141 | "website": "https://www.opera.com/"
142 | },
143 | {
144 | "name": "Opera GX",
145 | "logo": "/images/browser-logos/opera-gx.png",
146 | "website": "https://www.opera.com/gx"
147 | },
148 | {
149 | "name": "Vivaldi",
150 | "logo": "/images/browser-logos/vivaldi.png",
151 | "website": "https://vivaldi.com/"
152 | },
153 | {
154 | "name": "Vivaldi Snapshot",
155 | "logo": "/images/browser-logos/vivaldi-snapshot.png",
156 | "website": "https://vivaldi.com/"
157 | },
158 | {
159 | "name": "Yandex Browser",
160 | "logo": "/images/browser-logos/yandex.png",
161 | "website": "https://browser.yandex.com/"
162 | },
163 | {
164 | "name": "Yandex Browser Beta",
165 | "logo": "/images/browser-logos/yandex-beta.webp",
166 | "website": "https://browser.yandex.com/"
167 | },
168 | {
169 | "name": "Yandex Browser Alpha",
170 | "logo": "/images/browser-logos/yandex-alpha.png",
171 | "website": "https://browser.yandex.com/"
172 | },
173 | {
174 | "name": "Arc Browser",
175 | "logo": "/images/browser-logos/arc.png",
176 | "website": "https://arc.net/"
177 | },
178 | {
179 | "name": "Sigma OS",
180 | "logo": "/images/browser-logos/sigmaos.png",
181 | "website": "https://sigmaos.com/"
182 | },
183 | {
184 | "name": "Cromite",
185 | "logo": "/images/browser-logos/cromite.png",
186 | "website": "https://github.com/uazo/cromite"
187 | },
188 | {
189 | "name": "Kiwi",
190 | "logo": "/images/browser-logos/kiwi.png",
191 | "website": "https://kiwibrowser.com/"
192 | },
193 | {
194 | "name": "Via",
195 | "logo": "/images/browser-logos/via.png",
196 | "website": "https://www.viayoo.com/en/"
197 | },
198 | {
199 | "name": "Soul",
200 | "logo": "/images/browser-logos/soul.png",
201 | "website": "https://play.google.com/store/apps/details?id=com.mycompany.app.soulbrowser&hl=en"
202 | },
203 | {
204 | "name": "Quetta",
205 | "logo": "/images/browser-logos/quetta.png",
206 | "website": "https://www.quetta.net/"
207 | },
208 | {
209 | "name": "Thorium",
210 | "logo": "/images/browser-logos/thorium.webp",
211 | "website": "https://thorium.rocks/"
212 | },
213 | {
214 | "name": "Mull",
215 | "logo": "/images/browser-logos/mull.png",
216 | "website": "https://f-droid.org/en/packages/us.spotco.fennec_dos/"
217 | },
218 | {
219 | "name": "Icaraven",
220 | "logo": "/images/browser-logos/iceraven.png",
221 | "website": "https://github.com/fork-maintainers/iceraven-browser"
222 | },
223 | {
224 | "name": "Ghostery",
225 | "logo": "/images/browser-logos/ghostery.png",
226 | "website": "https://www.ghostery.com/ghostery-private-browser"
227 | },
228 | {
229 | "name": "Kito",
230 | "logo": "/images/browser-logos/kito.png",
231 | "website": "https://play.google.com/store/apps/details?id=com.yjllqint.kito&hl=en"
232 | },
233 | {
234 | "name": "Dia",
235 | "logo": "/images/browser-logos/dia.png",
236 | "website": "https://www.diabrowser.com/"
237 | },
238 | {
239 | "name": "Deta Surf",
240 | "logo": "/images/browser-logos/deta-surf.png",
241 | "website": "https://deta.surf/"
242 | },
243 | {
244 | "name": "Strawberry",
245 | "logo": "/images/browser-logos/strawberry.png",
246 | "website": "https://strawberrybrowser.com/"
247 | },
248 | {
249 | "name": "Fellou",
250 | "logo": "/images/browser-logos/fellou.jpg",
251 | "website": "https://fellou.ai/"
252 | },
253 | {
254 | "name": "BrowserOS",
255 | "logo": "/images/browser-logos/browseros.jpg",
256 | "website": "https://www.browseros.com/"
257 | },
258 | {
259 | "name": "Kosmik",
260 | "logo": "/images/browser-logos/kosmik.jpg",
261 | "website": "https://www.kosmik.app/"
262 | },
263 | {
264 | "name": "Neo",
265 | "logo": "/images/browser-logos/neo.jpg",
266 | "website": "https://neobrowser.ai/"
267 | },
268 | {
269 | "name": "Comet",
270 | "logo": "/images/browser-logos/comet.svg",
271 | "website": "https://www.perplexity.ai/comet"
272 | },
273 | {
274 | "name": "Ora",
275 | "logo": "/images/browser-logos/ora.png",
276 | "website": "https://www.orabrowser.com/"
277 | },
278 | {
279 | "name": "Helium",
280 | "logo": "/images/browser-logos/helium.jpg",
281 | "website": "https://helium.computer/"
282 | },
283 | {
284 | "name": "Web",
285 | "logo": "/images/browser-logos/web.png",
286 | "website": "https://github.com/nuance-dev/Web"
287 | },
288 | {
289 | "name": "Meteor",
290 | "logo": "/images/browser-logos/meteor.jpg",
291 | "website": "https://www.browse.dev/"
292 | },
293 | {
294 | "name": "Nook",
295 | "logo": "/images/browser-logos/nook.jpg",
296 | "website": "https://browsewithnook.com/"
297 | },
298 | {
299 | "name": "Shift",
300 | "logo": "/images/browser-logos/shift.jpg",
301 | "website": "https://shift.com/"
302 | }
303 | ]
304 |
--------------------------------------------------------------------------------
/app/components/Footer.js:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from "react";
2 |
3 | import Image from "next/image";
4 |
5 | const DONATION_ADDRESSES = {
6 | BTC: "bc1qfyad27catyr8rtdhhydn8ummf996kxtesuw4hr",
7 | XMR: "41zM5Hk39icMLDnbAckLpJHMwMPQKAQEADYA1AvjoZw9Y9NC7atnubrWPZKXWRbpZeGg66DkstQmA1oPZurRBcvRFbQ3PLs",
8 | LTC: "ltc1qnqldulnxsxpz4g89uklsepjeqx7cajynzyr7tc",
9 | MATIC: "0x6c056E9ccB183c08e9248eAF26160B5793221513",
10 | };
11 |
12 | export default function Footer() {
13 | const [isCopied, setIsCopied] = useState(false);
14 | const [copiedCurrency, setCopiedCurrency] = useState("");
15 | const [isMobile, setIsMobile] = useState(false);
16 |
17 | useEffect(() => {
18 | // Check if device is mobile
19 | const checkMobile = () => {
20 | setIsMobile(window.innerWidth < 768);
21 | };
22 |
23 | checkMobile();
24 | window.addEventListener("resize", checkMobile);
25 |
26 | return () => window.removeEventListener("resize", checkMobile);
27 | }, []);
28 |
29 | const handleCopy = (text, currency) => {
30 | navigator.clipboard.writeText(text);
31 | setIsCopied(true);
32 | setCopiedCurrency(currency);
33 | setTimeout(() => {
34 | setIsCopied(false);
35 | setCopiedCurrency("");
36 | }, 2000);
37 | };
38 |
39 | const truncateAddress = (address, type) => {
40 | if (isMobile) {
41 | if (type === "XMR") {
42 | return `${address.slice(0, 10)}...${address.slice(-10)}`;
43 | }
44 | return `${address.slice(0, 8)}...${address.slice(-8)}`;
45 | }
46 |
47 | if (type === "XMR") {
48 | return `${address.slice(0, 20)}...${address.slice(-20)}`;
49 | }
50 | return address;
51 | };
52 |
53 | return (
54 |
58 |
59 |
60 | {/* Social Links */}
61 |
62 |
63 |
148 |
149 |
150 | {/* Developer Info */}
151 |
189 |
190 | {/* Minimal Donations Section */}
191 |
195 |
Donations
196 |
197 | {isCopied
198 | ? `${copiedCurrency} address copied! ✓`
199 | : "Click to copy"}
200 |
201 |
202 | {Object.entries(DONATION_ADDRESSES).map(([currency, address]) => (
203 |
handleCopy(address, currency)}
206 | onKeyDown={(e) => {
207 | if (e.key === "Enter" || e.key === " ") {
208 | e.preventDefault();
209 | handleCopy(address, currency);
210 | }
211 | }}
212 | className="font-mono cursor-pointer text-[10px] sm:text-xs hover:text-gray-700 transition-colors p-1 rounded hover:bg-gray-100 dark:hover:bg-gray-800"
213 | tabIndex="0"
214 | role="button"
215 | aria-label={`Copy ${currency} address: ${address}`}
216 | >
217 | {currency}: {" "}
218 |
219 | {truncateAddress(address, currency)}
220 |
221 |
222 | ))}
223 |
224 |
225 |
226 | {/* Privacy Policy Link */}
227 |
228 |
232 | Privacy Policy
233 |
234 |
235 |
236 |
237 |
238 | );
239 | }
240 |
--------------------------------------------------------------------------------
/public/data/android.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "name": "Brave",
4 | "engine": "Blink",
5 | "versions": [
6 | {
7 | "version": "1.78.102",
8 | "scores": {
9 | "speedometer3": 8.08
10 | }
11 | },
12 | {
13 | "version": "1.69.164",
14 | "scores": {
15 | "speedometer3": 7.0
16 | }
17 | }
18 | ]
19 | },
20 | {
21 | "name": "Brave Beta",
22 | "engine": "Blink",
23 | "versions": [
24 | {
25 | "version": "1.70.107",
26 | "scores": {
27 | "speedometer3": 6.97
28 | }
29 | }
30 | ]
31 | },
32 | {
33 | "name": "Brave Nightly",
34 | "engine": "Blink",
35 | "versions": [
36 | {
37 | "version": "1.72.3",
38 | "scores": {
39 | "speedometer3": 6.93
40 | }
41 | }
42 | ]
43 | },
44 | {
45 | "name": "Cromite",
46 | "engine": "Blink",
47 | "versions": [
48 | {
49 | "version": "136.0.7103.125",
50 | "scores": {
51 | "speedometer3": 7.21
52 | }
53 | },
54 | {
55 | "version": "128.0.6613.120",
56 | "scores": {
57 | "speedometer3": 6.08
58 | }
59 | }
60 | ]
61 | },
62 | {
63 | "name": "DuckDuckGo Browser",
64 | "engine": "Blink",
65 | "versions": [
66 | {
67 | "version": "5.233.0",
68 | "scores": {
69 | "speedometer3": 9.07
70 | }
71 | },
72 | {
73 | "version": "5.213.0",
74 | "scores": {
75 | "speedometer3": 9.24
76 | }
77 | }
78 | ]
79 | },
80 | {
81 | "name": "Firefox",
82 | "engine": "Gecko",
83 | "versions": [
84 | {
85 | "version": "138.0.4",
86 | "scores": {
87 | "speedometer3": 5.04
88 | }
89 | },
90 | {
91 | "version": "130.0",
92 | "scores": {
93 | "speedometer3": 5.79
94 | }
95 | }
96 | ]
97 | },
98 | {
99 | "name": "Firefox Beta",
100 | "engine": "Gecko",
101 | "versions": [
102 | {
103 | "version": "131.0b5",
104 | "scores": {
105 | "speedometer3": 5.87
106 | }
107 | }
108 | ]
109 | },
110 | {
111 | "name": "Firefox Developer Edition",
112 | "engine": "Gecko",
113 | "versions": [
114 | {
115 | "version": "131.0b4",
116 | "scores": {
117 | "speedometer3": 5.87
118 | }
119 | }
120 | ]
121 | },
122 | {
123 | "name": "Firefox Nightly",
124 | "engine": "Gecko",
125 | "versions": [
126 | {
127 | "version": "132.0a1",
128 | "scores": {
129 | "speedometer3": 5.78
130 | }
131 | }
132 | ]
133 | },
134 | {
135 | "name": "Ghostery",
136 | "engine": "Gecko",
137 | "versions": [
138 | {
139 | "version": "1.0.2430",
140 | "scores": {
141 | "speedometer3": 4.14
142 | }
143 | }
144 | ]
145 | },
146 | {
147 | "name": "Google Chrome",
148 | "engine": "Blink",
149 | "versions": [
150 | {
151 | "version": "136.0.7103.126",
152 | "scores": {
153 | "speedometer3": 6.04
154 | }
155 | },
156 | {
157 | "version": "128.0.6613.146",
158 | "scores": {
159 | "speedometer3": 9.68
160 | }
161 | }
162 | ]
163 | },
164 | {
165 | "name": "Google Chrome Beta",
166 | "engine": "Blink",
167 | "versions": [
168 | {
169 | "version": "129.0.6668.38",
170 | "scores": {
171 | "speedometer3": 9.71
172 | }
173 | }
174 | ]
175 | },
176 | {
177 | "name": "Google Chrome Canary",
178 | "engine": "Blink",
179 | "versions": [
180 | {
181 | "version": "130.0.6715.0",
182 | "scores": {
183 | "speedometer3": 9.38
184 | }
185 | }
186 | ]
187 | },
188 | {
189 | "name": "Icaraven",
190 | "engine": "Gecko",
191 | "versions": [
192 | {
193 | "version": "2.31.0",
194 | "scores": {
195 | "speedometer3": 4.91
196 | }
197 | },
198 | {
199 | "version": "2.23.0",
200 | "scores": {
201 | "speedometer3": 5.94
202 | }
203 | }
204 | ]
205 | },
206 | {
207 | "name": "Kito",
208 | "engine": "Gecko",
209 | "versions": [
210 | {
211 | "version": "7.6.4.1",
212 | "scores": {
213 | "speedometer3": 3.95
214 | }
215 | }
216 | ]
217 | },
218 | {
219 | "name": "Kiwi",
220 | "engine": "Blink",
221 | "versions": [
222 | {
223 | "version": "124.0.6327.4",
224 | "scores": {
225 | "speedometer3": 5.37
226 | }
227 | }
228 | ]
229 | },
230 | {
231 | "name": "Microsoft Edge",
232 | "engine": "Blink",
233 | "versions": [
234 | {
235 | "version": "136.0.3240.91",
236 | "scores": {
237 | "speedometer3": 5.5
238 | }
239 | },
240 | {
241 | "version": "127.0.2651.1111",
242 | "scores": {
243 | "speedometer3": 5.55
244 | }
245 | }
246 | ]
247 | },
248 | {
249 | "name": "Microsoft Edge Beta",
250 | "engine": "Blink",
251 | "versions": [
252 | {
253 | "version": "129.0.2792.37",
254 | "scores": {
255 | "speedometer3": 5.04
256 | }
257 | }
258 | ]
259 | },
260 | {
261 | "name": "Microsoft Edge Canary",
262 | "engine": "Blink",
263 | "versions": [
264 | {
265 | "version": "130.0.2832.0",
266 | "scores": {
267 | "speedometer3": 5.58
268 | }
269 | }
270 | ]
271 | },
272 | {
273 | "name": "Mull",
274 | "engine": "Gecko",
275 | "versions": [
276 | {
277 | "version": "129.0.2",
278 | "scores": {
279 | "speedometer3": 3.54
280 | }
281 | }
282 | ]
283 | },
284 | {
285 | "name": "Opera",
286 | "engine": "Blink",
287 | "versions": [
288 | {
289 | "version": "89.3.4705.84083",
290 | "scores": {
291 | "speedometer3": 6.38
292 | }
293 | },
294 | {
295 | "version": "84.4.4452.81430",
296 | "scores": {
297 | "speedometer3": 5.59
298 | }
299 | }
300 | ]
301 | },
302 | {
303 | "name": "Opera Beta",
304 | "engine": "Blink",
305 | "versions": [
306 | {
307 | "version": "85.0.4475.81340",
308 | "scores": {
309 | "speedometer3": 5.49
310 | }
311 | }
312 | ]
313 | },
314 | {
315 | "name": "Opera GX",
316 | "engine": "Blink",
317 | "versions": [
318 | {
319 | "version": "2.7.5",
320 | "scores": {
321 | "speedometer3": 12.3
322 | }
323 | },
324 | {
325 | "version": "2.5.7",
326 | "scores": {
327 | "speedometer3": 8.99
328 | }
329 | }
330 | ]
331 | },
332 | {
333 | "name": "Opera Mini",
334 | "engine": "Blink",
335 | "versions": [
336 | {
337 | "version": "91.0.2254.77465",
338 | "scores": {
339 | "speedometer3": 8.41
340 | }
341 | },
342 | {
343 | "version": "84.0.2254.73823",
344 | "scores": {
345 | "speedometer3": 6.94
346 | }
347 | }
348 | ]
349 | },
350 | {
351 | "name": "Quetta",
352 | "engine": "Blink",
353 | "versions": [
354 | {
355 | "version": "1.5.5",
356 | "scores": {
357 | "speedometer3": 5.83
358 | }
359 | },
360 | {
361 | "version": "1.1.9",
362 | "scores": {
363 | "speedometer3": 4.37
364 | }
365 | }
366 | ]
367 | },
368 | {
369 | "name": "Samsung Internet",
370 | "engine": "Blink",
371 | "versions": [
372 | {
373 | "version": "28.0.0.59",
374 | "scores": {
375 | "speedometer3": 5.73
376 | }
377 | },
378 | {
379 | "version": "26.0.3.7",
380 | "scores": {
381 | "speedometer3": 5.99
382 | }
383 | }
384 | ]
385 | },
386 | {
387 | "name": "Samsung Internet Beta",
388 | "engine": "Blink",
389 | "versions": [
390 | {
391 | "version": "27.0.0.58",
392 | "scores": {
393 | "speedometer3": 6.81
394 | }
395 | }
396 | ]
397 | },
398 | {
399 | "name": "Soul",
400 | "engine": "Blink",
401 | "versions": [
402 | {
403 | "version": "1.4.72",
404 | "scores": {
405 | "speedometer3": 9.79
406 | }
407 | },
408 | {
409 | "version": "1.4.34",
410 | "scores": {
411 | "speedometer3": 9.14
412 | }
413 | }
414 | ]
415 | },
416 | {
417 | "name": "Thorium",
418 | "engine": "Blink",
419 | "versions": [
420 | {
421 | "version": "126.0.6478.246",
422 | "scores": {
423 | "speedometer3": 9.8
424 | }
425 | },
426 | {
427 | "version": "2.7.5",
428 | "scores": {
429 | "speedometer3": 7.46
430 | }
431 | }
432 | ]
433 | },
434 | {
435 | "name": "Via",
436 | "engine": "Blink",
437 | "versions": [
438 | {
439 | "version": "6.5.1",
440 | "scores": {
441 | "speedometer3": 10.95
442 | }
443 | },
444 | {
445 | "version": "5.9.0",
446 | "scores": {
447 | "speedometer3": 9.06
448 | }
449 | }
450 | ]
451 | },
452 | {
453 | "name": "Vivaldi",
454 | "engine": "Blink",
455 | "versions": [
456 | {
457 | "version": "7.4.3691.42",
458 | "scores": {
459 | "speedometer3": 8.57
460 | }
461 | },
462 | {
463 | "version": "6.9.3451.58",
464 | "scores": {
465 | "speedometer3": 6.93
466 | }
467 | }
468 | ]
469 | },
470 | {
471 | "name": "Vivaldi Snapshot",
472 | "engine": "Blink",
473 | "versions": [
474 | {
475 | "version": "6.10.3464.4",
476 | "scores": {
477 | "speedometer3": 6.47
478 | }
479 | }
480 | ]
481 | },
482 | {
483 | "name": "Waterfox",
484 | "engine": "Gecko",
485 | "versions": [
486 | {
487 | "version": "1.0.13",
488 | "scores": {
489 | "speedometer3": 3.8
490 | }
491 | },
492 | {
493 | "version": "1.0.8.2",
494 | "scores": {
495 | "speedometer3": 4.91
496 | }
497 | }
498 | ]
499 | },
500 | {
501 | "name": "Yandex Browser",
502 | "engine": "Blink",
503 | "versions": [
504 | {
505 | "version": "25.4.4.105",
506 | "scores": {
507 | "speedometer3": 7.8
508 | }
509 | },
510 | {
511 | "version": "24.7.6.41",
512 | "scores": {
513 | "speedometer3": 8.34
514 | }
515 | }
516 | ]
517 | },
518 | {
519 | "name": "Yandex Browser Alpha",
520 | "engine": "Blink",
521 | "versions": [
522 | {
523 | "version": "24.7.6.28",
524 | "scores": {
525 | "speedometer3": 8.1
526 | }
527 | }
528 | ]
529 | },
530 | {
531 | "name": "Yandex Browser Beta",
532 | "engine": "Blink",
533 | "versions": [
534 | {
535 | "version": "24.7.8.22",
536 | "scores": {
537 | "speedometer3": 8.13
538 | }
539 | }
540 | ]
541 | }
542 | ]
543 |
--------------------------------------------------------------------------------
/public/data/macos-intel.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "name": "Arc Browser",
4 | "engine": "Blink",
5 | "versions": [
6 | {
7 | "version": "1.66.0",
8 | "scores": {
9 | "speedometer3": 13.3
10 | }
11 | },
12 | {
13 | "version": "1.59.0",
14 | "scores": {
15 | "speedometer3": 12.4
16 | }
17 | },
18 | {
19 | "version": "1.57.1",
20 | "scores": {
21 | "speedometer3": 12.4
22 | }
23 | }
24 | ]
25 | },
26 | {
27 | "name": "Brave",
28 | "engine": "Blink",
29 | "versions": [
30 | {
31 | "version": "1.71.118",
32 | "scores": {
33 | "speedometer3": 13.33
34 | }
35 | },
36 | {
37 | "version": "1.69.162",
38 | "scores": {
39 | "speedometer3": 12.27
40 | }
41 | },
42 | {
43 | "version": "1.69.153",
44 | "scores": {
45 | "speedometer3": 12.2
46 | }
47 | },
48 | {
49 | "version": "1.68.141",
50 | "scores": {
51 | "speedometer3": 8.46
52 | }
53 | }
54 | ]
55 | },
56 | {
57 | "name": "DuckDuckGo Browser",
58 | "engine": "WebKit",
59 | "versions": [
60 | {
61 | "version": "1.110.0",
62 | "scores": {
63 | "speedometer3": 6.86
64 | }
65 | },
66 | {
67 | "version": "1.105.0",
68 | "scores": {
69 | "speedometer3": 6.53
70 | }
71 | },
72 | {
73 | "version": "1.102.0",
74 | "scores": {
75 | "speedometer3": 6.89
76 | }
77 | }
78 | ]
79 | },
80 | {
81 | "name": "Firefox",
82 | "engine": "Gecko",
83 | "versions": [
84 | {
85 | "version": "131.0.3",
86 | "scores": {
87 | "speedometer3": 13.5
88 | }
89 | },
90 | {
91 | "version": "130.0",
92 | "scores": {
93 | "speedometer3": 13.47
94 | }
95 | },
96 | {
97 | "version": "129.0.2",
98 | "scores": {
99 | "speedometer3": 13.07
100 | }
101 | },
102 | {
103 | "version": "123.0",
104 | "scores": {
105 | "speedometer3": 8.35
106 | }
107 | }
108 | ]
109 | },
110 | {
111 | "name": "Firefox Developer Edition",
112 | "engine": "Gecko",
113 | "versions": [
114 | {
115 | "version": "132.0b9",
116 | "scores": {
117 | "speedometer3": 13.4
118 | }
119 | },
120 | {
121 | "version": "131.0b4",
122 | "scores": {
123 | "speedometer3": 13.37
124 | }
125 | },
126 | {
127 | "version": "130.0b8",
128 | "scores": {
129 | "speedometer3": 13.1
130 | }
131 | },
132 | {
133 | "version": "130.0b3",
134 | "scores": {
135 | "speedometer3": 8.78
136 | }
137 | }
138 | ]
139 | },
140 | {
141 | "name": "Firefox Nightly",
142 | "engine": "Gecko",
143 | "versions": [
144 | {
145 | "version": "133.0a1",
146 | "scores": {
147 | "speedometer3": 13.13
148 | }
149 | },
150 | {
151 | "version": "132.0a1",
152 | "scores": {
153 | "speedometer3": 13.07
154 | }
155 | },
156 | {
157 | "version": "131.0a1",
158 | "scores": {
159 | "speedometer3": 13.03
160 | }
161 | },
162 | {
163 | "version": "130.0b3",
164 | "scores": {
165 | "speedometer3": 8.78
166 | }
167 | }
168 | ]
169 | },
170 | {
171 | "name": "Floorp",
172 | "engine": "Gecko",
173 | "versions": [
174 | {
175 | "version": "11.19.1",
176 | "scores": {
177 | "speedometer3": 13.27
178 | }
179 | },
180 | {
181 | "version": "11.18.1",
182 | "scores": {
183 | "speedometer3": 13.4
184 | }
185 | },
186 | {
187 | "version": "11.17.6",
188 | "scores": {
189 | "speedometer3": 12.97
190 | }
191 | }
192 | ]
193 | },
194 | {
195 | "name": "Google Chrome",
196 | "engine": "Blink",
197 | "versions": [
198 | {
199 | "version": "130.0.6723.70",
200 | "scores": {
201 | "speedometer3": 14.3
202 | }
203 | },
204 | {
205 | "version": "128.0.6613.121",
206 | "scores": {
207 | "speedometer3": 13.23
208 | }
209 | },
210 | {
211 | "version": "128.0.6613.85",
212 | "scores": {
213 | "speedometer3": 12.81
214 | }
215 | }
216 | ]
217 | },
218 | {
219 | "name": "Google Chrome Canary",
220 | "engine": "Blink",
221 | "versions": [
222 | {
223 | "version": "132.0.6799.0",
224 | "scores": {
225 | "speedometer3": 15.3
226 | }
227 | },
228 | {
229 | "version": "130.0.6710.0",
230 | "scores": {
231 | "speedometer3": 14.37
232 | }
233 | },
234 | {
235 | "version": "130.0.6673.0",
236 | "scores": {
237 | "speedometer3": 12.93
238 | }
239 | }
240 | ]
241 | },
242 | {
243 | "name": "Librewolf",
244 | "engine": "Gecko",
245 | "versions": [
246 | {
247 | "version": "131.0.3-1",
248 | "scores": {
249 | "speedometer3": 9.44
250 | }
251 | },
252 | {
253 | "version": "130.0-3",
254 | "scores": {
255 | "speedometer3": 9.33
256 | }
257 | },
258 | {
259 | "version": "129.0.1-1",
260 | "scores": {
261 | "speedometer3": 9.29
262 | }
263 | },
264 | {
265 | "version": "128.0-2",
266 | "scores": {
267 | "speedometer3": 6.06
268 | }
269 | }
270 | ]
271 | },
272 | {
273 | "name": "Microsoft Edge",
274 | "engine": "Blink",
275 | "versions": [
276 | {
277 | "version": "130.0.2849.56",
278 | "scores": {
279 | "speedometer3": 13.83
280 | }
281 | },
282 | {
283 | "version": "128.0.2739.67",
284 | "scores": {
285 | "speedometer3": 13.9
286 | }
287 | },
288 | {
289 | "version": "128.0.2739.42",
290 | "scores": {
291 | "speedometer3": 13.63
292 | }
293 | }
294 | ]
295 | },
296 | {
297 | "name": "Mullvad Browser",
298 | "engine": "Gecko",
299 | "versions": [
300 | {
301 | "version": "13.5.7",
302 | "scores": {
303 | "speedometer3": 5.42
304 | }
305 | },
306 | {
307 | "version": "13.5.3",
308 | "scores": {
309 | "speedometer3": 5.48
310 | }
311 | },
312 | {
313 | "version": "13.5.2",
314 | "scores": {
315 | "speedometer3": 5.5
316 | }
317 | }
318 | ]
319 | },
320 | {
321 | "name": "Opera",
322 | "engine": "Blink",
323 | "versions": [
324 | {
325 | "version": "114.0.5282.115",
326 | "scores": {
327 | "speedometer3": 9.8
328 | }
329 | },
330 | {
331 | "version": "113.0.5230.86",
332 | "scores": {
333 | "speedometer3": 9.38
334 | }
335 | },
336 | {
337 | "version": "113.0.5230.32",
338 | "scores": {
339 | "speedometer3": 9.15
340 | }
341 | }
342 | ]
343 | },
344 | {
345 | "name": "Opera GX",
346 | "engine": "Blink",
347 | "versions": [
348 | {
349 | "version": "114.0.5282.123",
350 | "scores": {
351 | "speedometer3": 12.7
352 | }
353 | },
354 | {
355 | "version": "113.0.5230.75",
356 | "scores": {
357 | "speedometer3": 13.03
358 | }
359 | },
360 | {
361 | "version": "112.0.5197.104",
362 | "scores": {
363 | "speedometer3": 12.27
364 | }
365 | }
366 | ]
367 | },
368 | {
369 | "name": "Orion",
370 | "engine": "WebKit",
371 | "versions": [
372 | {
373 | "version": "0.99.128.2.1-beta",
374 | "scores": {
375 | "speedometer3": 11.08
376 | }
377 | }
378 | ]
379 | },
380 | {
381 | "name": "Safari",
382 | "engine": "WebKit",
383 | "versions": [
384 | {
385 | "version": "17.6",
386 | "scores": {
387 | "speedometer3": 10.51
388 | }
389 | }
390 | ]
391 | },
392 | {
393 | "name": "Sigma OS",
394 | "engine": "WebKit",
395 | "versions": [
396 | {
397 | "version": "1.17.0.8",
398 | "scores": {
399 | "speedometer3": 4.82
400 | }
401 | },
402 | {
403 | "version": "1.17.0.6",
404 | "scores": {
405 | "speedometer3": 4.74
406 | }
407 | },
408 | {
409 | "version": "1.17.0",
410 | "scores": {
411 | "speedometer3": 4.84
412 | }
413 | }
414 | ]
415 | },
416 | {
417 | "name": "Tor Browser",
418 | "engine": "Gecko",
419 | "versions": [
420 | {
421 | "version": "14.0",
422 | "scores": {
423 | "speedometer3": 7.88
424 | }
425 | },
426 | {
427 | "version": "13.5.3",
428 | "scores": {
429 | "speedometer3": 5.43
430 | }
431 | },
432 | {
433 | "version": "12.5.2",
434 | "scores": {
435 | "speedometer3": 5.48
436 | }
437 | }
438 | ]
439 | },
440 | {
441 | "name": "Vivaldi",
442 | "engine": "Blink",
443 | "versions": [
444 | {
445 | "version": "7.0.3495.6",
446 | "scores": {
447 | "speedometer3": 11.9
448 | }
449 | },
450 | {
451 | "version": "6.9.3447.44",
452 | "scores": {
453 | "speedometer3": 12.47
454 | }
455 | },
456 | {
457 | "version": "6.8.3381.55",
458 | "scores": {
459 | "speedometer3": 13.03
460 | }
461 | }
462 | ]
463 | },
464 | {
465 | "name": "Waterfox",
466 | "engine": "Gecko",
467 | "versions": [
468 | {
469 | "version": "6.0.20",
470 | "scores": {
471 | "speedometer3": 8.56
472 | }
473 | },
474 | {
475 | "version": "6.0.19",
476 | "scores": {
477 | "speedometer3": 8.59
478 | }
479 | },
480 | {
481 | "version": "6.0.18",
482 | "scores": {
483 | "speedometer3": 8.56
484 | }
485 | }
486 | ]
487 | },
488 | {
489 | "name": "Yandex Browser",
490 | "engine": "Blink",
491 | "versions": [
492 | {
493 | "version": "24.10.1.616",
494 | "scores": {
495 | "speedometer3": 11.33
496 | }
497 | },
498 | {
499 | "version": "24.7.1.1144",
500 | "scores": {
501 | "speedometer3": 10.97
502 | }
503 | },
504 | {
505 | "version": "24.7.1.1116",
506 | "scores": {
507 | "speedometer3": 11.07
508 | }
509 | }
510 | ]
511 | },
512 | {
513 | "name": "Zen Browser",
514 | "engine": "Gecko",
515 | "versions": [
516 | {
517 | "version": "1.0.1-a.12",
518 | "scores": {
519 | "speedometer3": 11.97
520 | }
521 | },
522 | {
523 | "version": "1.0.0-a39",
524 | "scores": {
525 | "speedometer3": 11.87
526 | }
527 | },
528 | {
529 | "version": "1.0.0-a28",
530 | "scores": {
531 | "speedometer3": 11.5
532 | }
533 | }
534 | ]
535 | }
536 | ]
537 |
--------------------------------------------------------------------------------
/app/components/BrowserCard.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useRef, useState } from "react";
2 |
3 | import BrowserDetailsModal from "./BrowserDetailsModal";
4 | import Image from "next/image";
5 |
6 | const BrowserCard = React.memo(
7 | ({ browser, getEngineColor, rank, selectedPlatform, isLoading = false }) => {
8 | const [showModal, setShowModal] = useState(false);
9 | const [imageLoaded, setImageLoaded] = useState(false);
10 | const [focusVisible, setFocusVisible] = useState(false);
11 | const cardRef = useRef(null);
12 |
13 | const platformData = browser[selectedPlatform];
14 |
15 | // Handle keyboard navigation
16 | useEffect(() => {
17 | const handleKeyDown = (e) => {
18 | if (e.key === "Tab") {
19 | setFocusVisible(true);
20 | }
21 | };
22 |
23 | const handleMouseDown = () => {
24 | setFocusVisible(false);
25 | };
26 |
27 | document.addEventListener("keydown", handleKeyDown);
28 | document.addEventListener("mousedown", handleMouseDown);
29 |
30 | return () => {
31 | document.removeEventListener("keydown", handleKeyDown);
32 | document.removeEventListener("mousedown", handleMouseDown);
33 | };
34 | }, []);
35 |
36 | if (
37 | !platformData ||
38 | !platformData.versions ||
39 | platformData.versions.length === 0
40 | ) {
41 | return null;
42 | }
43 |
44 | const latestVersion = platformData.versions[0];
45 | const prevSpeedometer3Score =
46 | platformData.versions.length > 1
47 | ? platformData.versions[1].scores.speedometer3
48 | : null;
49 |
50 | const platformEngine = platformData.engine;
51 |
52 | const getRankStyle = (rank) => {
53 | const baseStyles = "relative overflow-hidden";
54 | switch (rank) {
55 | case 1:
56 | return `${baseStyles} ring-4 ring-yellow-400 shadow-xl shadow-yellow-400/20`;
57 | case 2:
58 | return `${baseStyles} ring-4 ring-gray-300 shadow-xl shadow-gray-300/20`;
59 | case 3:
60 | return `${baseStyles} ring-4 ring-amber-600 shadow-xl shadow-amber-600/20`;
61 | default:
62 | return baseStyles;
63 | }
64 | };
65 |
66 | const getRankBadge = (rank) => {
67 | if (rank > 3) return null;
68 |
69 | const badges = {
70 | 1: {
71 | text: "🏆 #1",
72 | color:
73 | "bg-gradient-to-r from-yellow-400 to-yellow-600 text-yellow-900",
74 | },
75 | 2: {
76 | text: "🥈 #2",
77 | color: "bg-gradient-to-r from-gray-300 to-gray-500 text-gray-900",
78 | },
79 | 3: {
80 | text: "🥉 #3",
81 | color: "bg-gradient-to-r from-amber-500 to-amber-700 text-amber-900",
82 | },
83 | };
84 |
85 | const badge = badges[rank];
86 | return (
87 |
90 | {badge.text}
91 |
92 | );
93 | };
94 |
95 | const scoreDifference = prevSpeedometer3Score
96 | ? latestVersion.scores.speedometer3 - prevSpeedometer3Score
97 | : null;
98 |
99 | const scoreChangeText = scoreDifference
100 | ? `${scoreDifference > 0 ? "Increased" : "Decreased"} by ${Math.abs(
101 | scoreDifference
102 | ).toFixed(2)} points from previous version`
103 | : "";
104 |
105 | const handleCardInteraction = (e) => {
106 | if (
107 | e.type === "click" ||
108 | (e.type === "keydown" && (e.key === "Enter" || e.key === " "))
109 | ) {
110 | if (e.type === "keydown") e.preventDefault();
111 | setShowModal(true);
112 | }
113 | };
114 |
115 | const getPerformanceLevel = (score) => {
116 | if (score >= 40)
117 | return {
118 | level: "Excellent",
119 | color: "text-green-600 dark:text-green-400",
120 | };
121 | if (score >= 30)
122 | return { level: "Good", color: "text-blue-600 dark:text-blue-400" };
123 | if (score >= 20)
124 | return { level: "Fair", color: "text-yellow-600 dark:text-yellow-400" };
125 | return { level: "Poor", color: "text-red-600 dark:text-red-400" };
126 | };
127 |
128 | const performance = getPerformanceLevel(latestVersion.scores.speedometer3);
129 |
130 | if (isLoading) {
131 | return (
132 |
133 |
134 |
138 |
142 |
143 | {[1, 2, 3].map((i) => (
144 |
148 | ))}
149 |
150 |
151 |
152 | );
153 | }
154 |
155 | return (
156 | <>
157 |
183 | {getRankBadge(rank)}
184 |
185 |
186 | {/* Header Section */}
187 |
251 |
252 | {/* Metadata Section */}
253 |
254 |
255 | v{latestVersion.version}
256 |
257 |
262 | {platformEngine}
263 |
264 |
265 |
266 | {/* Performance Metrics */}
267 |
271 | {/* Speedometer Score */}
272 |
273 |
274 | Speedometer 3.1
275 |
276 |
277 |
280 | {latestVersion.scores.speedometer3.toFixed(1)}
281 |
282 | {scoreDifference !== null && (
283 |
284 | 0
287 | ? "bg-green-100 dark:bg-green-900/30 text-green-800 dark:text-green-400"
288 | : scoreDifference < 0
289 | ? "bg-red-100 dark:bg-red-900/30 text-red-800 dark:text-red-400"
290 | : "bg-gray-100 dark:bg-gray-700 text-gray-600 dark:text-gray-400"
291 | }`}
292 | >
293 | {scoreDifference > 0
294 | ? "↗"
295 | : scoreDifference < 0
296 | ? "↘"
297 | : "→"}
298 | {Math.abs(scoreDifference).toFixed(1)}
299 |
300 |
301 | )}
302 |
303 |
304 |
305 | {/* RAM Usage */}
306 | {latestVersion.scores.ram && (
307 |
308 |
309 | Memory Usage
310 |
311 |
312 | {latestVersion.scores.ram >= 1000
313 | ? `${(latestVersion.scores.ram / 1000).toFixed(1)}GB`
314 | : `${latestVersion.scores.ram.toFixed(0)}MB`}
315 |
316 |
317 | )}
318 |
319 | {/* Adblock Score */}
320 | {latestVersion.scores.adblock && (
321 |
322 |
323 | Ad Blocking
324 |
325 |
326 | {latestVersion.scores.adblock.toFixed(0)}%
327 |
328 |
329 |
= 80
332 | ? "bg-green-500"
333 | : latestVersion.scores.adblock >= 60
334 | ? "bg-yellow-500"
335 | : "bg-red-500"
336 | }`}
337 | style={{ width: `${latestVersion.scores.adblock}%` }}
338 | role="progressbar"
339 | aria-valuenow={latestVersion.scores.adblock}
340 | aria-valuemin="0"
341 | aria-valuemax="100"
342 | aria-label={`Ad blocking effectiveness: ${latestVersion.scores.adblock}%`}
343 | />
344 |
345 |
346 | )}
347 |
348 |
349 | {/* Action Hint */}
350 |
351 |
352 | Click for detailed history
353 |
354 |
355 |
356 |
357 |
358 | {showModal && (
359 |
setShowModal(false)}
363 | />
364 | )}
365 | >
366 | );
367 | }
368 | );
369 |
370 | BrowserCard.displayName = "BrowserCard";
371 |
372 | export default BrowserCard;
373 |
--------------------------------------------------------------------------------
/app/components/Header.js:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from "react";
2 |
3 | import DarkModeToggle from "./DarkModeToggle";
4 | import Image from "next/image";
5 | import Link from "next/link";
6 |
7 | export default function Header({ darkMode, toggleDarkMode }) {
8 | const [isVisible, setIsVisible] = useState(false);
9 | const [currentPlatform, setCurrentPlatform] = useState(0);
10 |
11 | const platforms = [
12 | { name: "macOS", icon: "🍎", color: "from-blue-500 to-purple-500" },
13 | { name: "Windows", icon: "🪟", color: "from-blue-600 to-cyan-500" },
14 | { name: "Android", icon: "🤖", color: "from-green-500 to-emerald-500" },
15 | { name: "iPad", icon: "📱", color: "from-purple-500 to-pink-500" },
16 | ];
17 |
18 | // Animation on mount
19 | useEffect(() => {
20 | setIsVisible(true);
21 | }, []);
22 |
23 | // Rotating platform showcase
24 | useEffect(() => {
25 | const interval = setInterval(() => {
26 | setCurrentPlatform((prev) => (prev + 1) % platforms.length);
27 | }, 3000);
28 | return () => clearInterval(interval);
29 | }, [platforms.length]);
30 |
31 | const currentDate = new Date().toLocaleDateString("en-US", {
32 | year: "numeric",
33 | month: "long",
34 | day: "numeric",
35 | });
36 |
37 | return (
38 |
42 | {/* Animated Background Pattern */}
43 |
44 |
49 |
50 |
57 |
58 |
59 |
60 |
68 |
69 |
75 |
83 |
84 |
85 |
86 |
87 |
88 |
89 | {/* Floating geometric shapes */}
90 |
91 |
95 |
99 |
103 |
107 |
108 |
109 | {/* Dark Mode Toggle */}
110 |
111 |
112 |
113 |
114 | {/* Main Content */}
115 |
116 |
121 | {/* Top Section - Logo and Navigation */}
122 |
123 | {/* Logo */}
124 |
145 |
146 | {/* Quick Stats */}
147 |
148 |
149 |
150 | 100+
151 |
152 |
153 | Browsers Tested
154 |
155 |
156 |
157 |
158 | 5
159 |
160 |
161 | Platforms
162 |
163 |
164 |
165 |
166 | Monthly
167 |
168 |
169 | Updates
170 |
171 |
172 |
173 |
174 |
175 | {/* Hero Section */}
176 |
177 | {/* Main Title */}
178 |
185 |
186 | Browserating
187 |
188 |
189 |
190 | {/* Subtitle with animated platform showcase */}
191 |
198 |
199 | Browser Performance Ranking for
200 |
201 |
202 | {/* Animated Platform Showcase */}
203 |
204 | {platforms.map((platform) => (
205 |
209 | {platform.icon}
210 | {platform.name}
211 |
212 | ))}
213 |
214 |
215 |
216 | {/* Description */}
217 |
224 |
225 | Discover the fastest browsers across different platforms using
226 | the industry-standard
227 |
228 | {" "}
229 | Speedometer 3.1 benchmark
230 |
231 | . Our comprehensive testing reveals real-world performance
232 | differences to help you choose the best browser for your needs.
233 |
234 |
235 | {/* Key Features */}
236 | {/*
237 |
238 |
243 |
248 |
249 |
Real-world Testing
250 |
251 |
252 |
257 |
262 |
263 |
Cross-Platform
264 |
265 |
266 |
271 |
276 |
277 |
Monthly Updates
278 |
279 |
*/}
280 |
281 |
282 | {/* Call to Action */}
283 |
330 |
331 | {/* Last Updated Info */}
332 |
339 |
340 |
341 |
342 |
343 |
344 | Last updated:
345 |
346 |
347 |
348 |
349 |
353 | December 9, 2025
354 |
355 |
356 | {/* ? Tooltip */}
357 |
358 | ?
359 |
360 |
361 |
362 | I ran into several issues during this testing cycle, so
363 | results will be rolled out gradually. Follow me on X
364 | (@kawaiier101) for updates.
365 |
366 |
367 |
368 |
369 |
370 |
371 |
372 | Next update:
373 |
374 | ~ January 10, 2026
375 |
376 |
377 |
378 |
379 |
380 | 💡 Want weekly updates?
381 |
385 | Support the project
386 | {" "}
387 | to get more frequent performance insights and help us test more
388 | browsers!
389 |
390 |
391 |
392 |
393 |
394 |
395 | {/* Bottom Wave */}
396 |
397 |
403 |
408 |
413 |
414 |
415 |
416 | );
417 | }
418 |
--------------------------------------------------------------------------------
/app/components/BrowserBarChart.js:
--------------------------------------------------------------------------------
1 | import { useEffect, useMemo, useRef, useState } from "react";
2 |
3 | export default function BrowserBarChart({
4 | browsers,
5 | platform,
6 | getEngineColor,
7 | }) {
8 | const [sortOrder, setSortOrder] = useState("desc");
9 | const [hoveredBar, setHoveredBar] = useState(null);
10 | const [selectedBars, setSelectedBars] = useState([]);
11 | const chartRef = useRef(null);
12 |
13 | const chartData = useMemo(() => {
14 | if (!browsers || !platform) return [];
15 |
16 | let data = browsers
17 | .filter((browser) => {
18 | const platformData = browser[platform];
19 | const scores = platformData?.versions?.[0]?.scores;
20 | return scores && typeof scores.speedometer3 === "number";
21 | })
22 | .map((browser) => {
23 | const platformData = browser[platform];
24 | const currentScore = platformData.versions[0].scores.speedometer3;
25 | const previousScore = platformData.versions[1]?.scores?.speedometer3;
26 |
27 | return {
28 | name: browser.name,
29 | score: currentScore,
30 | previousScore: previousScore,
31 | trend: previousScore
32 | ? ((currentScore - previousScore) / previousScore) * 100
33 | : 0,
34 | engine: platformData.engine || "unknown",
35 | ramUsage: platformData.versions[0].scores.ram,
36 | adblockScore: platformData.versions[0].scores.adblock,
37 | };
38 | });
39 |
40 | // Sort data based on selected order
41 | switch (sortOrder) {
42 | case "asc":
43 | return data.sort((a, b) => a.score - b.score);
44 | case "alphabetical":
45 | return data.sort((a, b) => a.name.localeCompare(b.name));
46 | default: // desc
47 | return data.sort((a, b) => b.score - a.score);
48 | }
49 | }, [browsers, platform, sortOrder]);
50 |
51 | const maxScore = useMemo(() => {
52 | return Math.max(...chartData.map((item) => item.score), 1);
53 | }, [chartData]);
54 |
55 | // Performance categories
56 | const getPerformanceCategory = (score) => {
57 | if (score >= maxScore * 0.9)
58 | return {
59 | label: "Excellent",
60 | color: "text-green-600 dark:text-green-400",
61 | };
62 | if (score >= maxScore * 0.7)
63 | return { label: "Good", color: "text-blue-600 dark:text-blue-400" };
64 | if (score >= maxScore * 0.5)
65 | return { label: "Fair", color: "text-yellow-600 dark:text-yellow-400" };
66 | return { label: "Poor", color: "text-red-600 dark:text-red-400" };
67 | };
68 |
69 | const handleBarClick = (itemName) => {
70 | setSelectedBars((prev) =>
71 | prev.includes(itemName)
72 | ? prev.filter((name) => name !== itemName)
73 | : [...prev, itemName]
74 | );
75 | };
76 |
77 | const handleKeyDown = (e, itemName) => {
78 | if (e.key === "Enter" || e.key === " ") {
79 | e.preventDefault();
80 | handleBarClick(itemName);
81 | }
82 | };
83 |
84 | // Clear selection when clicking outside
85 | useEffect(() => {
86 | const handleClickOutside = (event) => {
87 | if (chartRef.current && !chartRef.current.contains(event.target)) {
88 | setSelectedBars([]);
89 | }
90 | };
91 |
92 | document.addEventListener("mousedown", handleClickOutside);
93 | return () => document.removeEventListener("mousedown", handleClickOutside);
94 | }, []);
95 |
96 | if (!browsers || !platform || !getEngineColor) {
97 | console.warn("BrowserBarChart: Missing required props");
98 | return null;
99 | }
100 |
101 | if (chartData.length === 0) {
102 | return (
103 |
104 |
105 |
120 |
121 | No Performance Data
122 |
123 |
124 | No performance data available for the selected platform and filters.
125 |
126 |
127 |
128 | );
129 | }
130 |
131 | const platformNames = {
132 | "macos-arm": "macOS ARM",
133 | "macos-intel": "macOS Intel",
134 | windows: "Windows",
135 | android: "Android",
136 | ipad: "iPad OS",
137 | };
138 |
139 | const platformName = platformNames[platform] || platform;
140 |
141 | return (
142 |
143 | {/* Header */}
144 |
145 |
146 |
147 |
148 | Performance Comparison
149 |
150 |
151 | Speedometer 3.1 scores on {platformName} • {chartData.length}{" "}
152 | browsers
153 |
154 |
155 |
156 | {/* Controls */}
157 |
158 |
159 |
163 | Sort:
164 |
165 | setSortOrder(e.target.value)}
169 | className="text-sm border border-gray-300 dark:border-gray-600 rounded-lg px-3 py-1.5 bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-purple-500"
170 | >
171 | Highest First
172 | Lowest First
173 | Alphabetical
174 |
175 |
176 |
177 | {selectedBars.length > 0 && (
178 |
setSelectedBars([])}
180 | className="text-sm px-3 py-1.5 text-purple-600 hover:text-purple-700 dark:text-purple-400 dark:hover:text-purple-300 font-medium"
181 | >
182 | Clear Selection ({selectedBars.length})
183 |
184 | )}
185 |
186 |
187 |
188 | {/* Legend */}
189 |
190 |
191 |
192 |
193 | Excellent (90-100%)
194 |
195 |
196 |
197 |
198 |
199 | Good (70-89%)
200 |
201 |
202 |
203 |
204 |
205 | Fair (50-69%)
206 |
207 |
208 |
209 |
210 |
211 | Poor (<50%)
212 |
213 |
214 |
215 |
216 |
217 | {/* Chart */}
218 |
219 |
226 |
233 | {chartData.map((item, index) => {
234 | const percentHeight = (item.score / maxScore) * 100;
235 | const barHeight = Math.max(percentHeight * 3.2, 20); // Minimum 20px height, scale by 3.2 for visibility
236 | const scoreFormatted = item.score.toLocaleString(undefined, {
237 | maximumFractionDigits: 1,
238 | });
239 | const isHovered = hoveredBar === item.name;
240 | const isSelected = selectedBars.includes(item.name);
241 | const performance = getPerformanceCategory(item.score);
242 |
243 | return (
244 |
handleBarClick(item.name)}
248 | onKeyDown={(e) => handleKeyDown(e, item.name)}
249 | onMouseEnter={() => setHoveredBar(item.name)}
250 | onMouseLeave={() => setHoveredBar(null)}
251 | tabIndex="0"
252 | role="button"
253 | aria-pressed={isSelected}
254 | aria-label={`${item.name}: ${scoreFormatted} points using ${
255 | item.engine
256 | } engine${
257 | item.trend !== 0
258 | ? `, trend: ${
259 | item.trend > 0 ? "+" : ""
260 | }${item.trend.toFixed(1)}%`
261 | : ""
262 | }`}
263 | style={{ height: "400px" }}
264 | >
265 | {/* Rank and Score */}
266 |
267 |
268 | #{index + 1}
269 |
270 |
271 | {scoreFormatted}
272 |
273 | {item.trend !== 0 && (
274 |
0
277 | ? "text-green-600 dark:text-green-400"
278 | : "text-red-600 dark:text-red-400"
279 | }`}
280 | >
281 | {item.trend > 0 ? "↗" : "↘"}{" "}
282 | {Math.abs(item.trend).toFixed(1)}%
283 |
284 | )}
285 |
286 |
287 | {/* Bar Container */}
288 |
292 | {/* Bar */}
293 |
306 |
315 | {/* Performance indicator */}
316 |
= maxScore * 0.9
319 | ? "bg-green-400"
320 | : item.score >= maxScore * 0.7
321 | ? "bg-blue-400"
322 | : item.score >= maxScore * 0.5
323 | ? "bg-yellow-400"
324 | : "bg-red-400"
325 | }`}
326 | >
327 |
328 | {/* Hover tooltip */}
329 | {isHovered && (
330 |
331 |
{item.name}
332 |
Score: {scoreFormatted}
333 |
Engine: {item.engine}
334 | {item.ramUsage && (
335 |
RAM: {item.ramUsage.toFixed(0)} MB
336 | )}
337 | {item.adblockScore && (
338 |
339 | Adblock: {item.adblockScore.toFixed(0)}%
340 |
341 | )}
342 |
343 |
344 | )}
345 |
346 |
347 |
348 |
349 | {/* Browser name and engine */}
350 |
351 |
357 | {item.name}
358 |
359 |
364 | {item.engine}
365 |
366 |
367 |
368 | );
369 | })}
370 |
371 |
372 |
373 | {/* Chart Instructions */}
374 |
375 |
376 | Click or tap bars to select • Hover for details •
377 |
378 | {" "}
379 | Scroll horizontally to view all browsers
380 |
381 | Swipe to scroll
382 |
383 |
384 |
385 |
386 | {/* Selected Browser Comparison */}
387 | {selectedBars.length > 1 && (
388 |
389 |
390 | Comparison ({selectedBars.length} selected)
391 |
392 |
393 | {chartData
394 | .filter((item) => selectedBars.includes(item.name))
395 | .map((item) => (
396 |
400 |
401 |
402 | {item.name}
403 |
404 |
handleBarClick(item.name)}
406 | className="text-gray-400 hover:text-gray-600 dark:hover:text-gray-300"
407 | aria-label={`Remove ${item.name} from comparison`}
408 | >
409 |
414 |
419 |
420 |
421 |
422 |
423 |
424 | Score:{" "}
425 |
426 | {item.score.toFixed(1)}
427 |
428 |
429 |
430 | Engine: {item.engine}
431 |
432 | {item.ramUsage && (
433 |
434 | RAM:{" "}
435 |
436 | {item.ramUsage.toFixed(0)} MB
437 |
438 |
439 | )}
440 | {item.adblockScore && (
441 |
442 | Adblock:{" "}
443 |
444 | {item.adblockScore.toFixed(0)}%
445 |
446 |
447 | )}
448 |
449 |
450 | ))}
451 |
452 |
453 | )}
454 |
455 | {/* Screen reader summary */}
456 |
457 |
Summary of browser performance on {platformName}
458 |
459 | Sorted by{" "}
460 | {sortOrder === "desc"
461 | ? "highest to lowest"
462 | : sortOrder === "asc"
463 | ? "lowest to highest"
464 | : "alphabetical order"}
465 | :
466 |
467 |
468 | {chartData.map((item, index) => (
469 |
470 | {item.name} ranked #{index + 1} with a score of{" "}
471 | {item.score.toFixed(1)} using {item.engine} engine
472 | {item.trend !== 0 &&
473 | `, showing a ${
474 | item.trend > 0 ? "positive" : "negative"
475 | } trend of ${Math.abs(item.trend).toFixed(1)}%`}
476 |
477 | ))}
478 |
479 |
480 |
481 | );
482 | }
483 |
--------------------------------------------------------------------------------
/app/components/About/About.js:
--------------------------------------------------------------------------------
1 | import { useState } from "react";
2 |
3 | export default function About() {
4 | const [activeSection, setActiveSection] = useState("methodology");
5 | const [expandedSystem, setExpandedSystem] = useState(null);
6 |
7 | const systemConfigs = [
8 | {
9 | id: "macos-silicon",
10 | title: "macOS (Apple Silicon)",
11 | icon: "🍎",
12 | gradient: "from-blue-500 to-purple-500",
13 | specs: {
14 | os: "macOS Tahoe 26.1",
15 | device: "14-inch MacBook Pro (2023)",
16 | processor: "M3 Pro",
17 | memory: "36 GB RAM",
18 | highlights: ["Apple Silicon", "Latest macOS", "High Performance"],
19 | },
20 | },
21 | {
22 | id: "macos-intel",
23 | title: "macOS (Intel)",
24 | icon: "💻",
25 | gradient: "from-gray-500 to-blue-500",
26 | specs: {
27 | os: "macOS Ventura 13.6.9",
28 | device: "15-inch MacBook Pro (2019)",
29 | processor: "2.3 GHz 8-core Intel Core i9",
30 | memory: "16 GB RAM",
31 | highlights: [
32 | "Intel Architecture",
33 | "Stable Release",
34 | "Professional Grade",
35 | ],
36 | },
37 | },
38 | {
39 | id: "windows",
40 | title: "Windows",
41 | icon: "🪟",
42 | gradient: "from-blue-600 to-cyan-500",
43 | specs: {
44 | os: "Windows 10 Pro",
45 | device: "Lenovo Ideapad Gaming 3",
46 | processor: "AMD Ryzen 5 5600H with Radeon Graphics 3.3 GHz",
47 | memory: "16 GB RAM",
48 | highlights: ["Gaming Laptop", "AMD Architecture", "Real-world Setup"],
49 | },
50 | },
51 | {
52 | id: "android",
53 | title: "Android",
54 | icon: "🤖",
55 | gradient: "from-green-500 to-emerald-500",
56 | specs: {
57 | os: "Nothing OS 2.6 (Android 14)",
58 | device: "Nothing Phone (2a)",
59 | processor: "Dimensity 7200 Pro CPU with Mali-G610 MC4 GPU",
60 | memory: "8 GB RAM",
61 | highlights: ["Modern Android", "Mid-range Performance", "Custom OS"],
62 | },
63 | },
64 | {
65 | id: "ipad",
66 | title: "iPad",
67 | icon: "📱",
68 | gradient: "from-purple-500 to-pink-500",
69 | specs: {
70 | os: "iPadOS 18.5",
71 | device: "iPad Mini 7th Generation",
72 | processor: "A17 Pro CPU",
73 | memory: "8 GB RAM",
74 | highlights: ["Latest iPadOS", "Pro Chip", "Compact Form Factor"],
75 | },
76 | },
77 | ];
78 |
79 | const testingSteps = [
80 | {
81 | icon: "⚡",
82 | title: "Speedometer 3.1 Benchmark",
83 | description:
84 | "Five tests conducted per browser, eliminating best and worst results, averaging the middle three for accuracy.",
85 | details:
86 | "The benchmark tests a wide range of JavaScript frameworks and technologies, including TodoMVC implementations (using vanilla JavaScript, Web Components, React, Angular, Vue, jQuery, Preact, Svelte, and Lit), code and rich text editors (CodeMirror, TipTap), and charting libraries (observable-plot, chartjs, React-Stockcharts-SVG, Perf-Dashboard). It also includes workloads that mimic browsing a typical news site, testing how well a browser handles large DOM and CSSOM changes during navigation.",
87 | },
88 | {
89 | icon: "🧠",
90 | title: "Memory Usage Analysis",
91 | description:
92 | "Cumulative RAM consumption measured across seven diverse websites including IGN, ESPN, Figma, and Reddit.",
93 | details:
94 | "Memory tracking via Activity Monitor provides real-world usage patterns rather than theoretical limits. All processes RAM usage is summed up to get the total RAM usage.",
95 | },
96 | {
97 | icon: "🛡️",
98 | title: "Ad-Blocking Effectiveness",
99 | description:
100 | "Comprehensive testing using AdBlock Tester to evaluate built-in and extension-based blocking capabilities.",
101 | details:
102 | "Tests various ad types including display ads, video ads, trackers, and social media widgets.",
103 | },
104 | ];
105 |
106 | const scoreGuide = [
107 | {
108 | metric: "Speedometer 3.1",
109 | description:
110 | "Higher scores indicate faster JavaScript and DOM performance",
111 | scale: "0-100+",
112 | good: "40+",
113 | average: "25-40",
114 | poor: "<25",
115 | color: "text-blue-600 dark:text-blue-400",
116 | },
117 | {
118 | metric: "RAM Usage",
119 | description: "Lower values indicate more efficient memory management",
120 | scale: "MB",
121 | good: "<500MB",
122 | average: "500-1000MB",
123 | poor: ">1000MB",
124 | color: "text-green-600 dark:text-green-400",
125 | },
126 | {
127 | metric: "Ad Blocking",
128 | description: "Higher scores indicate better ad-blocking capabilities",
129 | scale: "0-100%",
130 | good: "80-100%",
131 | average: "50-80%",
132 | poor: "<50%",
133 | color: "text-purple-600 dark:text-purple-400",
134 | },
135 | ];
136 |
137 | const sections = [
138 | { id: "methodology", label: "Testing Methodology", icon: "🔬" },
139 | { id: "systems", label: "Test Systems", icon: "💻" },
140 | { id: "scores", label: "Score Guide", icon: "📊" },
141 | ];
142 |
143 | return (
144 |
149 | {/* Header */}
150 |
151 |
155 | Testing Methodology & Systems
156 |
157 |
158 | Transparent, consistent, and thorough testing across multiple
159 | platforms to give you reliable browser performance insights you can
160 | trust.
161 |
162 |
163 |
164 | {/* Navigation Tabs */}
165 |
166 | {sections.map((section) => (
167 | setActiveSection(section.id)}
170 | className={`flex items-center gap-2 px-6 py-3 rounded-xl font-medium transition-all duration-300 ${
171 | activeSection === section.id
172 | ? "bg-gradient-to-r from-purple-600 to-blue-600 text-white shadow-lg scale-105"
173 | : "bg-gray-100 dark:bg-gray-800 text-gray-700 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-700"
174 | }`}
175 | >
176 | {section.icon}
177 | {section.label}
178 |
179 | ))}
180 |
181 |
182 | {/* Content Sections */}
183 |
184 | {/* Testing Methodology */}
185 | {activeSection === "methodology" && (
186 |
187 |
188 | {testingSteps.map((step, index) => (
189 |
190 |
191 |
192 |
193 | {step.icon}
194 |
195 |
196 |
197 |
198 | {step.title}
199 |
200 |
201 | {step.description}
202 |
203 |
204 |
205 | Technical Details →
206 |
207 |
208 | {step.details}
209 |
210 |
211 |
212 |
213 |
214 | ))}
215 |
216 |
217 | {/* Key Points */}
218 |
219 |
220 | ✨
221 | Why Our Testing Matters
222 |
223 |
224 |
225 | ✓
226 |
227 | Consistent testing environment across all browsers
228 |
229 |
230 |
231 | ✓
232 |
233 | Statistical accuracy through multiple test runs
234 |
235 |
236 |
237 | ✓
238 |
239 | Real-world scenarios and websites
240 |
241 |
242 |
243 |
244 |
245 | )}
246 |
247 | {/* Test Systems */}
248 | {activeSection === "systems" && (
249 |
250 |
251 | {systemConfigs.map((system) => (
252 |
258 | setExpandedSystem(
259 | expandedSystem === system.id ? null : system.id,
260 | )
261 | }
262 | >
263 |
266 |
267 |
268 |
{system.icon}
269 |
270 |
271 | {system.title}
272 |
273 |
274 | Click to{" "}
275 | {expandedSystem === system.id
276 | ? "collapse"
277 | : "expand"}{" "}
278 | details
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 | Operating System:
287 |
288 |
289 | {system.specs.os}
290 |
291 |
292 |
293 |
294 | Device:
295 |
296 |
297 | {system.specs.device}
298 |
299 |
300 |
301 | {expandedSystem === system.id && (
302 |
303 |
304 |
305 | Processor:
306 |
307 |
308 | {system.specs.processor}
309 |
310 |
311 |
312 |
313 | Memory:
314 |
315 |
316 | {system.specs.memory}
317 |
318 |
319 |
320 |
321 |
322 | Key Features:
323 |
324 |
325 | {system.specs.highlights.map(
326 | (highlight, index) => (
327 |
331 | {highlight}
332 |
333 | ),
334 | )}
335 |
336 |
337 |
338 | )}
339 |
340 |
341 |
342 |
343 | ))}
344 |
345 |
346 |
347 |
348 |
⚠️
349 |
350 |
351 | Important Testing Notes
352 |
353 |
354 | Performance results may vary based on your specific hardware
355 | configuration, operating system version, installed
356 | extensions, and system load. These tests represent
357 | controlled conditions and should be used as relative
358 | comparisons rather than absolute benchmarks.
359 |
360 |
361 |
362 |
363 |
364 | )}
365 |
366 | {/* Score Guide */}
367 | {activeSection === "scores" && (
368 |
369 |
370 |
371 |
372 | 🎯
373 | Understanding Performance Metrics
374 |
375 |
376 |
377 | Higher Speedometer scores = Faster browser performance.
378 |
379 | Our comprehensive testing evaluates multiple aspects of
380 | browser performance to give you a complete picture.
381 |
382 |
383 |
384 |
385 |
386 | {scoreGuide.map((metric, index) => (
387 |
391 |
392 |
395 |
396 | {index === 0 ? "⚡" : index === 1 ? "🧠" : "🛡️"}
397 |
398 |
399 |
400 |
403 | {metric.metric}
404 |
405 |
406 | {metric.description}
407 |
408 |
409 |
410 |
411 |
412 | Scale:
413 |
414 |
415 | {metric.scale}
416 |
417 |
418 |
419 |
420 | Excellent:
421 |
422 |
423 | {metric.good}
424 |
425 |
426 |
427 |
428 | Average:
429 |
430 |
431 | {metric.average}
432 |
433 |
434 |
435 |
436 | Needs Improvement:
437 |
438 |
439 | {metric.poor}
440 |
441 |
442 |
443 |
444 |
445 |
446 | ))}
447 |
448 |
449 |
450 |
451 | 💡
452 | Pro Tips for Interpreting Results
453 |
454 |
455 |
456 | →
457 |
458 | Focus on consistent performance across metrics rather than
459 | just peak scores
460 |
461 |
462 |
463 | →
464 |
465 | Consider your specific use case: gaming, productivity, or
466 | general browsing
467 |
468 |
469 |
470 | →
471 |
472 | Balance performance with features that matter to you
473 |
474 |
475 |
476 | →
477 |
478 | Remember that browser updates can significantly impact
479 | performance
480 |
481 |
482 |
483 |
484 |
485 | )}
486 |
487 |
488 | );
489 | }
490 |
--------------------------------------------------------------------------------