From 7af6eafb41284a66beff87257c28ef1cc0953952 Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Wed, 3 Jun 2026 07:02:37 -0500 Subject: [PATCH] feat(stats): add geo breakdown (#30456) --- bun.lock | 28 +++ packages/stats/app/package.json | 12 +- packages/stats/app/src/routes/index.css | 203 ++++++++++++++++++++++ packages/stats/app/src/routes/index.tsx | 220 +++++++++++++++++++++++- packages/stats/core/src/domain/home.ts | 4 +- 5 files changed, 462 insertions(+), 5 deletions(-) diff --git a/bun.lock b/bun.lock index 95190cbd8..83193bd70 100644 --- a/bun.lock +++ b/bun.lock @@ -671,17 +671,25 @@ "@solidjs/meta": "catalog:", "@solidjs/router": "catalog:", "@solidjs/start": "catalog:", + "d3-geo": "3.1.1", "d3-scale": "4.0.2", "effect": "catalog:", + "i18n-iso-countries": "7.14.0", "nitro": "3.0.1-alpha.1", "solid-js": "catalog:", "sst": "catalog:", + "topojson-client": "3.1.0", "vite": "catalog:", + "world-atlas": "2.0.2", }, "devDependencies": { "@cloudflare/workers-types": "catalog:", "@types/bun": "catalog:", + "@types/d3-geo": "3.1.0", "@types/d3-scale": "4.0.9", + "@types/geojson": "7946.0.16", + "@types/topojson-client": "3.1.5", + "@types/topojson-specification": "1.0.5", "@typescript/native-preview": "catalog:", "typescript": "catalog:", }, @@ -2466,6 +2474,8 @@ "@types/cross-spawn": ["@types/cross-spawn@6.0.6", "", { "dependencies": { "@types/node": "*" } }, "sha512-fXRhhUkG4H3TQk5dBhQ7m/JDdSNHKwR2BBia62lhwEIq9xGiQKLxd6LymNhn47SjXhsUEPmxi+PKw2OkW4LLjA=="], + "@types/d3-geo": ["@types/d3-geo@3.1.0", "", { "dependencies": { "@types/geojson": "*" } }, "sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ=="], + "@types/d3-scale": ["@types/d3-scale@4.0.9", "", { "dependencies": { "@types/d3-time": "*" } }, "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw=="], "@types/d3-time": ["@types/d3-time@3.0.4", "", {}, "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g=="], @@ -2486,6 +2496,8 @@ "@types/fs-extra": ["@types/fs-extra@9.0.13", "", { "dependencies": { "@types/node": "*" } }, "sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA=="], + "@types/geojson": ["@types/geojson@7946.0.16", "", {}, "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg=="], + "@types/hast": ["@types/hast@3.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ=="], "@types/http-cache-semantics": ["@types/http-cache-semantics@4.2.0", "", {}, "sha512-L3LgimLHXtGkWikKnsPg0/VFx9OGZaC+eN1u4r+OB1XRqH3meBIAVC2zr1WdMH+RHmnRkqliQAOHNJ/E0j/e0Q=="], @@ -2568,6 +2580,10 @@ "@types/ssri": ["@types/ssri@7.1.5", "", { "dependencies": { "@types/node": "*" } }, "sha512-odD/56S3B51liILSk5aXJlnYt99S6Rt9EFDDqGtJM26rKHApHcwyU/UoYHrzKkdkHMAIquGWCuHtQTbes+FRQw=="], + "@types/topojson-client": ["@types/topojson-client@3.1.5", "", { "dependencies": { "@types/geojson": "*", "@types/topojson-specification": "*" } }, "sha512-C79rySTyPxnQNNguTZNI1Ct4D7IXgvyAs3p9HPecnl6mNrJ5+UhvGNYcZfpROYV2lMHI48kJPxwR+F9C6c7nmw=="], + + "@types/topojson-specification": ["@types/topojson-specification@1.0.5", "", { "dependencies": { "@types/geojson": "*" } }, "sha512-C7KvcQh+C2nr6Y2Ub4YfgvWvWCgP2nOQMtfhlnwsRL4pYmmwzBS7HclGiS87eQfDOU/DLQpX6GEscviaz4yLIQ=="], + "@types/trusted-types": ["@types/trusted-types@2.0.7", "", {}, "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw=="], "@types/tsscmp": ["@types/tsscmp@1.0.2", "", {}, "sha512-cy7BRSU8GYYgxjcx0Py+8lo5MthuDhlyu076KUcYzVNXL23luYgRHkMG2fIFEc6neckeh/ntP82mw+U4QjZq+g=="], @@ -3048,6 +3064,8 @@ "d3-format": ["d3-format@3.1.2", "", {}, "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg=="], + "d3-geo": ["d3-geo@3.1.1", "", { "dependencies": { "d3-array": "2.5.0 - 3" } }, "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q=="], + "d3-interpolate": ["d3-interpolate@3.0.1", "", { "dependencies": { "d3-color": "1 - 3" } }, "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g=="], "d3-scale": ["d3-scale@4.0.2", "", { "dependencies": { "d3-array": "2.10.0 - 3", "d3-format": "1 - 3", "d3-interpolate": "1.2.0 - 3", "d3-time": "2.1.1 - 3", "d3-time-format": "2 - 4" } }, "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ=="], @@ -3124,6 +3142,8 @@ "dfa": ["dfa@1.2.0", "", {}, "sha512-ED3jP8saaweFTjeGX8HQPjeC1YYyZs98jGNZx6IiBvxW7JG5v492kamAQB3m2wop07CvU/RQmzcKr6bgcC5D/Q=="], + "diacritics": ["diacritics@1.3.0", "", {}, "sha512-wlwEkqcsaxvPJML+rDh/2iS824jbREk6DUMUKkEaSlxdYHeS43cClJtsWglvw2RfeXGm6ohKDqsXteJ5sP5enA=="], + "didyoumean": ["didyoumean@1.2.2", "", {}, "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw=="], "diff": ["diff@8.0.2", "", {}, "sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg=="], @@ -3598,6 +3618,8 @@ "husky": ["husky@9.1.7", "", { "bin": { "husky": "bin.js" } }, "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA=="], + "i18n-iso-countries": ["i18n-iso-countries@7.14.0", "", { "dependencies": { "diacritics": "1.3.0" } }, "sha512-nXHJZYtNrfsi1UQbyRqm3Gou431elgLjKl//CYlnBGt5aTWdRPH1PiS2T/p/n8Q8LnqYqzQJik3Q7mkwvLokeg=="], + "i18next": ["i18next@23.16.8", "", { "dependencies": { "@babel/runtime": "^7.23.2" } }, "sha512-06r/TitrM88Mg5FdUXAKL96dJMzgqLE5dv3ryBAra4KCwD9mJ4ndOTS95ZuymIGoE+2hzfdaMak2X11/es7ZWg=="], "iconv-corefoundation": ["iconv-corefoundation@1.1.7", "", { "dependencies": { "cli-truncate": "^2.1.0", "node-addon-api": "^1.6.3" }, "os": "darwin" }, "sha512-T10qvkw0zz4wnm560lOEg0PovVqUXuOFhhHAkixw8/sycy7TJt7v/RrkEKEQnAw2viPSJu6iAkErxnzR0g8PpQ=="], @@ -4918,6 +4940,8 @@ "toolbeam-docs-theme": ["toolbeam-docs-theme@0.4.8", "", { "peerDependencies": { "@astrojs/starlight": "^0.34.3", "astro": "^5.7.13" } }, "sha512-b+5ynEFp4Woe5a22hzNQm42lD23t13ZMihVxHbzjA50zdcM9aOSJTIjdJ0PDSd4/50HbBXcpHiQsz6rM4N88ww=="], + "topojson-client": ["topojson-client@3.1.0", "", { "dependencies": { "commander": "2" }, "bin": { "topo2geo": "bin/topo2geo", "topomerge": "bin/topomerge", "topoquantize": "bin/topoquantize" } }, "sha512-605uxS6bcYxGXw9qi62XyrV6Q3xwbndjachmNxu8HWTtVPxZfEJN9fd/SZS1Q54Sn2y0TMyMxFj/cJINqGHrKw=="], + "tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="], "traverse": ["traverse@0.3.9", "", {}, "sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ=="], @@ -5174,6 +5198,8 @@ "workerd": ["workerd@1.20251118.0", "", { "optionalDependencies": { "@cloudflare/workerd-darwin-64": "1.20251118.0", "@cloudflare/workerd-darwin-arm64": "1.20251118.0", "@cloudflare/workerd-linux-64": "1.20251118.0", "@cloudflare/workerd-linux-arm64": "1.20251118.0", "@cloudflare/workerd-windows-64": "1.20251118.0" }, "bin": { "workerd": "bin/workerd" } }, "sha512-Om5ns0Lyx/LKtYI04IV0bjIrkBgoFNg0p6urzr2asekJlfP18RqFzyqMFZKf0i9Gnjtz/JfAS/Ol6tjCe5JJsQ=="], + "world-atlas": ["world-atlas@2.0.2", "", {}, "sha512-IXfV0qwlKXpckz1FhwXVwKRjiIhOnWttOskm5CtxMsjgE/MXAYRHWJqgXOpM8IkcPBoXnyTU5lFHcYa5ChG0LQ=="], + "wrangler": ["wrangler@4.50.0", "", { "dependencies": { "@cloudflare/kv-asset-handler": "0.4.0", "@cloudflare/unenv-preset": "2.7.11", "blake3-wasm": "2.1.5", "esbuild": "0.25.4", "miniflare": "4.20251118.1", "path-to-regexp": "6.3.0", "unenv": "2.0.0-rc.24", "workerd": "1.20251118.0" }, "optionalDependencies": { "fsevents": "~2.3.2" }, "peerDependencies": { "@cloudflare/workers-types": "^4.20251118.0" }, "optionalPeers": ["@cloudflare/workers-types"], "bin": { "wrangler": "bin/wrangler.js", "wrangler2": "bin/wrangler.js" } }, "sha512-+nuZuHZxDdKmAyXOSrHlciGshCoAPiy5dM+t6mEohWm7HpXvTHmWQGUf/na9jjWlWJHCJYOWzkA1P5HBJqrIEA=="], "wrap-ansi": ["wrap-ansi@9.0.2", "", { "dependencies": { "ansi-styles": "^6.2.1", "string-width": "^7.0.0", "strip-ansi": "^7.1.0" } }, "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww=="], @@ -6152,6 +6178,8 @@ "tiny-async-pool/semver": ["semver@5.7.2", "", { "bin": { "semver": "bin/semver" } }, "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g=="], + "topojson-client/commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="], + "tree-sitter-bash/node-addon-api": ["node-addon-api@8.7.0", "", {}, "sha512-9MdFxmkKaOYVTV+XVRG8ArDwwQ77XIgIPyKASB1k3JPq3M8fGQQQE3YpMOrKm6g//Ktx8ivZr8xo1Qmtqub+GA=="], "tw-to-css/postcss": ["postcss@8.4.31", "", { "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } }, "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ=="], diff --git a/packages/stats/app/package.json b/packages/stats/app/package.json index 0a8275c37..9904dc49a 100644 --- a/packages/stats/app/package.json +++ b/packages/stats/app/package.json @@ -18,17 +18,25 @@ "@solidjs/meta": "catalog:", "@solidjs/router": "catalog:", "@solidjs/start": "catalog:", + "d3-geo": "3.1.1", "d3-scale": "4.0.2", "effect": "catalog:", + "i18n-iso-countries": "7.14.0", "nitro": "3.0.1-alpha.1", - "sst": "catalog:", "solid-js": "catalog:", - "vite": "catalog:" + "sst": "catalog:", + "topojson-client": "3.1.0", + "vite": "catalog:", + "world-atlas": "2.0.2" }, "devDependencies": { "@cloudflare/workers-types": "catalog:", "@types/bun": "catalog:", + "@types/d3-geo": "3.1.0", "@types/d3-scale": "4.0.9", + "@types/geojson": "7946.0.16", + "@types/topojson-client": "3.1.5", + "@types/topojson-specification": "1.0.5", "@typescript/native-preview": "catalog:", "typescript": "catalog:" }, diff --git a/packages/stats/app/src/routes/index.css b/packages/stats/app/src/routes/index.css index 5fc35cdb9..576c28e59 100644 --- a/packages/stats/app/src/routes/index.css +++ b/packages/stats/app/src/routes/index.css @@ -1647,6 +1647,7 @@ :is( [data-section="leaderboard"], [data-section="market-share"], + [data-section="geo-breakdown"], [data-section="token-cost"], [data-section="cache-ratio"], [data-section="session-cost"] @@ -2123,6 +2124,191 @@ white-space: nowrap; } +[data-page="stats"] [data-component="geo-breakdown"] { + display: grid; + gap: 16px; + align-items: start; +} + +[data-page="stats"] [data-slot="geo-map-panel"] { + position: relative; + min-width: 0; + overflow: hidden; + background: var(--stats-layer); + border: 1px solid var(--stats-line); +} + +[data-page="stats"] [data-component="geo-world-map"] { + display: block; + width: 100%; + height: auto; +} + +[data-page="stats"] [data-slot="geo-countries"] path { + fill: var(--stats-layer-2); + stroke: var(--stats-bg); + stroke-width: 0.45px; + transition: + fill 140ms ease, + opacity 140ms ease; +} + +[data-page="stats"] [data-slot="geo-countries"] path[data-has-data="true"] { + fill: var(--stats-accent); + opacity: var(--geo-country-opacity); + cursor: pointer; +} + +[data-page="stats"] [data-slot="geo-countries"] path[data-active="true"] { + fill: color-mix(in srgb, var(--stats-accent) 70%, var(--stats-text)); + opacity: 1; +} + +[data-page="stats"] [data-slot="geo-borders"] { + fill: none; + stroke: var(--stats-line-strong); + stroke-linejoin: round; + stroke-width: 0.6px; + pointer-events: none; +} + +[data-page="stats"] [data-slot="geo-active-country"] { + position: absolute; + bottom: 16px; + left: 16px; + display: grid; + gap: 8px; + min-width: 168px; + max-width: calc(100% - 32px); + box-sizing: border-box; + padding: 12px; + background: color-mix(in srgb, var(--stats-bg) 92%, transparent); + box-shadow: + 0 0 0 0.5px var(--stats-line-strong), + 0 6px 16px #0000000d, + 0 2px 6px #0000000f; +} + +[data-page="stats"] [data-slot="geo-active-country"] span, +[data-page="stats"] [data-slot="geo-active-country"] em { + color: var(--stats-faint); + font-style: normal; +} + +[data-page="stats"] [data-slot="geo-active-country"] span { + font-size: 10px; + font-weight: 600; + line-height: 1; +} + +[data-page="stats"] [data-slot="geo-active-country"] strong { + min-width: 0; + overflow: hidden; + color: var(--stats-text); + font-size: 16px; + font-weight: 600; + line-height: 1.2; + text-overflow: ellipsis; + white-space: nowrap; +} + +[data-page="stats"] [data-slot="geo-active-country"] p { + display: flex; + align-items: center; + justify-content: space-between; + gap: 16px; + color: var(--stats-muted); + font-size: 11px; + font-weight: 500; + line-height: 1; +} + +[data-page="stats"] [data-slot="geo-active-country"] b { + color: var(--stats-accent-text); + font-weight: 600; +} + +[data-page="stats"] [data-component="geo-country-list"] { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(min(100%, 212px), 1fr)); + align-content: start; + gap: 8px 10px; + min-width: 0; + margin: 20px 0 0; + padding: 0; + list-style: none; +} + +[data-page="stats"] [data-component="geo-country-list"] li { + min-width: 0; +} + +[data-page="stats"] [data-component="geo-country-list"] button { + display: grid; + grid-template-columns: 28px 8px minmax(0, 1fr) auto auto; + align-items: center; + gap: 10px; + width: 100%; + min-width: 0; + height: 32px; + padding: 0 8px; + border: 1px solid var(--stats-line); + border-radius: 0; + background: var(--stats-layer); + color: var(--stats-muted); + font-size: 11px; + line-height: 1; + text-align: left; + transition: + border-color 120ms ease, + background 120ms ease, + box-shadow 120ms ease; +} + +[data-page="stats"] [data-component="geo-country-list"] button[data-active="true"], +[data-page="stats"] [data-component="geo-country-list"] button:focus-visible { + border-color: var(--stats-text); + background: var(--stats-layer); + color: var(--stats-text); + box-shadow: + 0 0 0 0.5px color-mix(in srgb, var(--stats-text) 70%, transparent), + 0 1px 2px -1px #00000014, + 0 2px 4px #0000000a; +} + +[data-page="stats"] [data-component="geo-country-list"] span { + color: var(--stats-faint); + font-weight: 500; + text-align: center; +} + +[data-page="stats"] [data-component="geo-country-list"] i { + width: 8px; + height: 8px; + background: var(--stats-accent); + opacity: var(--geo-row-opacity); +} + +[data-page="stats"] [data-component="geo-country-list"] strong { + min-width: 0; + overflow: hidden; + color: var(--stats-text); + font-weight: 600; + text-overflow: ellipsis; + white-space: nowrap; +} + +[data-page="stats"] [data-component="geo-country-list"] em, +[data-page="stats"] [data-component="geo-country-list"] b { + color: var(--stats-faint); + font-style: normal; +} + +[data-page="stats"] [data-component="geo-country-list"] b { + color: var(--stats-muted); + font-weight: 500; +} + [data-page="stats"] [data-component="token-cost"], [data-page="stats"] [data-component="cache-ratio"] { position: relative; @@ -2734,6 +2920,7 @@ [data-page="stats"] [data-section="top-models"], [data-page="stats"] [data-section="leaderboard"], [data-page="stats"] [data-section="market-share"], + [data-page="stats"] [data-section="geo-breakdown"], [data-page="stats"] [data-section="token-cost"], [data-page="stats"] [data-section="cache-ratio"], [data-page="stats"] [data-section="session-cost"] { @@ -2866,6 +3053,7 @@ [data-page="stats"] [data-section="top-models"], [data-page="stats"] [data-section="leaderboard"], [data-page="stats"] [data-section="market-share"], + [data-page="stats"] [data-section="geo-breakdown"], [data-page="stats"] [data-section="token-cost"], [data-page="stats"] [data-section="cache-ratio"], [data-page="stats"] [data-section="session-cost"] { @@ -2960,6 +3148,21 @@ height: 400px; } + [data-page="stats"] [data-slot="geo-active-country"] { + position: static; + min-width: 0; + max-width: none; + margin: 0 12px 12px; + } + + [data-page="stats"] [data-component="geo-country-list"] button { + grid-template-columns: 26px 8px minmax(0, 1fr) auto; + } + + [data-page="stats"] [data-component="geo-country-list"] b { + display: none; + } + [data-page="stats"] [data-component="top-models-chart"][data-dense-labels="true"], [data-page="stats"] [data-component="market-share"][data-dense-labels="true"] { overflow-x: auto; diff --git a/packages/stats/app/src/routes/index.tsx b/packages/stats/app/src/routes/index.tsx index be7d664ca..073347db5 100644 --- a/packages/stats/app/src/routes/index.tsx +++ b/packages/stats/app/src/routes/index.tsx @@ -1,6 +1,11 @@ import "./index.css" import { Link, Meta, Title } from "@solidjs/meta" import { ProviderIcon } from "@opencode-ai/ui/provider-icon" +import { geoEquirectangular, geoPath } from "d3-geo" +import { scaleSqrt } from "d3-scale" +import countryCodesSource from "i18n-iso-countries/codes.json?raw" +import { feature, mesh } from "topojson-client" +import countriesTopologySource from "world-atlas/countries-110m.json?raw" import ibmPlexMonoRegularLatin1 from "@ibm/plex/IBM-Plex-Mono/fonts/split/woff2/IBMPlexMono-Regular-Latin1.woff2?url" import ibmPlexMonoMediumLatin1 from "@ibm/plex/IBM-Plex-Mono/fonts/split/woff2/IBMPlexMono-Medium-Latin1.woff2?url" import ibmPlexMonoSemiBoldLatin1 from "@ibm/plex/IBM-Plex-Mono/fonts/split/woff2/IBMPlexMono-SemiBold-Latin1.woff2?url" @@ -10,6 +15,7 @@ import statsUnfurlRankings from "../asset/unfurl-rankings.png?url" import { getStatsHomeData, type CacheRatioEntry, + type CountryEntry, type LeaderboardEntry, type MarketDay, type StatsHomeData, @@ -21,6 +27,8 @@ import { runtime } from "@opencode-ai/stats-core/runtime" import { createAsync, query } from "@solidjs/router" import { createEffect, createMemo, createSignal, For, onCleanup, onMount, Show, type JSX } from "solid-js" import { getRequestEvent } from "solid-js/web" +import type { FeatureCollection, GeometryObject, GeoJsonProperties } from "geojson" +import type { GeometryCollection, Topology } from "topojson-specification" const products = ["All Users", "Zen", "Go"] as const const tokenProducts = ["Zen", "Go"] as const @@ -42,6 +50,7 @@ const headerLinks = [ { href: "#token-cost", label: "Token Cost" }, { href: "#cache-ratio", label: "Cache Ratio" }, { href: "#market-share", label: "Market Share" }, + { href: "#geo-breakdown", label: "Geo Breakdown" }, ] as const const githubLink = { href: "https://github.com/anomalyco/opencode", @@ -75,11 +84,43 @@ const themePreferenceLabels = { system: "System", } as const const themeStorageKey = "opencode:stats-theme" +const geoMapWidth = 960 +const geoMapHeight = 430 +const countryDisplayNames = new Intl.DisplayNames(["en"], { type: "region" }) type UsageProduct = (typeof products)[number] type TokenProduct = (typeof tokenProducts)[number] type UsageRange = (typeof ranges)[number] type ThemePreference = (typeof themePreferences)[number] +type IsoCountryCode = readonly [string, string, string] +type WorldCountryProperties = GeoJsonProperties & { name?: string } +type WorldTopology = Topology<{ countries: GeometryCollection }> + +const countryNumericIds = new Map( + (JSON.parse(countryCodesSource) as IsoCountryCode[]).map((country) => [country[0], country[2]] as const), +) +const worldTopology = JSON.parse(countriesTopologySource) as WorldTopology +const worldCountryGeometries: GeometryCollection = { + ...worldTopology.objects.countries, + geometries: worldTopology.objects.countries.geometries.filter((country) => String(country.id ?? "") !== "010"), +} +const worldCountries = feature( + worldTopology, + worldCountryGeometries, +) as FeatureCollection +const worldProjection = geoEquirectangular().fitExtent( + [ + [10, 12], + [geoMapWidth - 10, geoMapHeight - 12], + ], + worldCountries, +) +const worldPath = geoPath(worldProjection) +const worldCountryPaths = worldCountries.features.map((country) => ({ + id: String(country.id ?? "").padStart(3, "0"), + path: worldPath(country) ?? "", +})) +const worldBorderPath = worldPath(mesh(worldTopology, worldCountryGeometries, (a, b) => a !== b)) ?? "" const getData = query(async () => { "use server" @@ -165,6 +206,7 @@ export default function StatsHome() { + )} @@ -1194,6 +1236,181 @@ function MarketShareList(props: { ) } +function GeoBreakdownSection(props: { data: StatsHomeData["country"] }) { + const [activeCountry, setActiveCountry] = createSignal() + const data = createMemo(() => props.data["2M"]) + const countryById = createMemo( + () => + new Map( + data().flatMap((country) => { + const id = countryNumericId(country.country) + return id ? [[id, country] as const] : [] + }), + ), + ) + const maxTokens = createMemo(() => Math.max(0, ...data().map((country) => country.tokens)) || 1) + const topCountries = createMemo(() => data().slice(0, 15)) + const active = createMemo(() => data().find((country) => country.country === activeCountry()) ?? data()[0]) + + return ( +
{ + if (event.pointerType === "touch") return + setActiveCountry(undefined) + }} + > + + + 0} + fallback={} + > +
+
+ + + {(country) => ( +
+ #{String(country().rank).padStart(2, "0")} + {formatCountryName(country().country)} +

+ {formatGeoTokens(country().tokens)} + {formatGeoShare(country().share)} +

+
+ )} +
+
+ +
+
+
+ ) +} + +function GeoWorldMap(props: { + countryById: Map + activeCountry: string | undefined + maxTokens: number + onActiveCountryChange: (country: string | undefined) => void +}) { + const opacityScale = createMemo(() => scaleSqrt().domain([0, props.maxTokens]).range([0.26, 0.96]).clamp(true)) + const countryOpacity = (country: CountryEntry | undefined) => { + if (!country) return 0 + const opacity = opacityScale()(country.tokens) + if (!props.activeCountry || props.activeCountry === country.country) return opacity + return Math.max(0.18, opacity * 0.36) + } + + return ( + + Geo Breakdown map + + + {(country) => { + const entry = () => props.countryById.get(country.id) + return ( + + + + + ) +} + +function GeoCountryList(props: { + data: CountryEntry[] + activeCountry: string | undefined + maxTokens: number + onActiveCountryChange: (country: string | undefined) => void +}) { + const opacityScale = createMemo(() => scaleSqrt().domain([0, props.maxTokens]).range([0.26, 0.96]).clamp(true)) + + return ( +
    + + {(country) => ( +
  1. + +
  2. + )} +
    +
+ ) +} + +function countryNumericId(country: string) { + return countryNumericIds.get(country.toUpperCase())?.padStart(3, "0") +} + +function formatCountryName(country: string) { + const code = country.toUpperCase() + if (code === "ZZ") return "Unknown" + if (!countryNumericId(code)) return code + return countryDisplayNames.of(code) ?? code +} + +function formatGeoTokens(value: number) { + if (value >= 1) return formatTrillions(value) + if (value >= 0.001) return `${Number((value * 1000).toFixed(value >= 0.01 ? 0 : 1))}B` + return `${Math.round(value * 1_000_000)}M` +} + +function formatGeoShare(value: number) { + return `${value.toFixed(value > 0 && value < 1 ? 1 : 0)}%` +} + function getMarketSegmentColor(author: string, color: string, activeAuthor: string | undefined) { if (!activeAuthor) return color if (activeAuthor === author) return color @@ -1747,6 +1964,7 @@ function Footer(props: { { href: "#token-cost", label: "Token Cost" }, { href: "#cache-ratio", label: "Cache Ratio" }, { href: "#market-share", label: "Market Share" }, + { href: "#geo-breakdown", label: "Geo Breakdown" }, ] const legal = [ { href: "https://opencode.ai/legal/terms-of-service", label: "Terms of service" }, @@ -1762,7 +1980,7 @@ function Footer(props: { return (