community-leaderboard
GitHub用于生成并每日发布社区模型排行榜图片至 Discord。包含手动构建、设计决策及品牌规范说明,支持基于 Token 量的排名与稳定性展示。
Trigger Scenarios
Install
npx skills add pollinations/pollinations --skill community-leaderboard -g -y
SKILL.md
Frontmatter
{
"name": "community-leaderboard",
"description": "Generate and post the daily community-model leaderboard image to Discord. Use when asked to build, regenerate, redesign, or post the community model leaderboard, or when extending its design (e.g. new stat panels, palette changes).",
"allowed-tools": "Bash"
}
Community model leaderboard
Daily pixel-art image posted to #dev-community-models ranking community text
models by tokens served in the last 24h, with a speed panel and per-model
success badges. Generated by
operations/community-monitor/leaderboard/build-leaderboard.mjs, run
automatically by the community-monitor EC2 agent's CYCLE.md duty 3b (once/day,
~12:00 UTC).
Regenerating manually
cd operations/community-monitor/leaderboard
TB_TOKEN=<token> node build-leaderboard.mjs --dry-run # preview HTML only, no render/upload
TB_TOKEN=<token> POLLI_TOKEN=<token> node build-leaderboard.mjs # full render + upload, prints markdown
--dry-run writes /tmp/leaderboard-preview.html and skips chromium/upload —
use it to sanity-check the Tinybird query and ranking without spending an
upload. The real run only works where chromium and python3-pil are
installed (currently just the community-monitor box — see Rendering below).
Design decisions (read before changing anything)
These came out of several rounds of live feedback — don't relitigate them without a reason:
- Ranked by tokens served, not request count. Request count rewards chatty small-completion models over models doing real work. A model with 4× the requests but 1/3 the tokens should NOT outrank the token leader — this was the single most important correction during design.
- Tokens are the headline number, both as a hero counter at the top
(
57,468,899 TOKENS · 24H) and as the leading column on every row — deliberately placed before the model name, not after, so the eye reads magnitude first. - Stability is a per-row badge, not its own leaderboard. An early
version had a separate "most stable" panel; killed because most models sit
at or near 100% and ties make the ranking meaningless. Now it's a status
indicator only: a lime
PERFECTbadge at exactly 100%, pixel hearts (♥♥♥ ≥99%, ♥♥ ≥95%, ♥ ≥80%) below that, a skull below 80%. The PERFECT badge matters — celebrate the models that never failed, don't just lump them into a heart tier. - Speed gets its own small panel below the main board (median tokens/sec, not mean — outliers from cold starts/timeouts skew the mean badly), not mixed into the main ranking. Top 3 by speed, gold card for #1.
- Minimal text, maximal graphic. No paragraph explaining the board — headline number, column headers, bars. If you're tempted to add explanatory prose, add a stat instead.
- No avatars/rank badges in the main leaderboard board (kept for the companion "Arena" scatter concept, not the primary board) — a crown on the #1 row is enough ceremony.
Brand system
- Fonts: Press Start 2P (headings/scores, pixel/arcade feel) + IBM Plex
Mono (body/labels). Both embedded as base64 data-URI
@font-faceinfonts-embedded.css— required, not optional. This board is designed to render standalone via chromium screenshot, which has no network access to Google Fonts inside the sandboxed render; without embedding, text silently falls back to a generic mono and looks broken. If you ever see a render with non-blocky headings, check the font embed first.- Regenerating
fonts-embedded.cssif a font ever needs to change: fetch the woff2 fromhttps://fonts.googleapis.com/css2?family=<name>(a normal browser UA is required — the default curl UA gets served an old ttf format), base64-encode eachsrc: url(...)and inline it as a data URI in a@font-faceblock. Keep it to the Latin subset only — full Unicode coverage bloats the file for zero benefit on an English-only board.
- Regenerating
- Palette (validated against the
datavizskill's accessibility checks): cream#F3EBDEbackground, ink#110518text/borders, hard offset box-shadows (6px 6px 0 #110518, zero border-radius — this is the house pixel/arcade look, seepollinations.ai/src/ui/components/TopContributors.tsxfor the same vocabulary used elsewhere in the product). Chart-legal categorical hues derived from brand colors via same-hue OKLCH adjustment (not the raw brand pastels, which fail contrast/CVD checks): periwinkle#5978df(speed bars), lavender#8338b3, mint/status-stable#3b9736, status-watch#b8860b, status-degraded#b03a2e. - Layout: fixed 1200px width (Discord embed width), height determined by content (10 rows + speed panel), cropped post-render — see Rendering.
Rendering (chromium on the community-monitor box)
No headless-browser npm dependency (puppeteer, playwright) — the box runs
the chromium snap directly via execFileSync, screenshotting a local HTML
file. Constraints discovered the hard way, all already handled in
build-leaderboard.mjs:
--no-sandboxis required — snap confinement blocks the normal Chrome sandbox.- Never write chromium's output into a dot-prefixed directory (e.g.
/home/ubuntu/.foo/) — snap's AppArmor profile silently denies the write withPermission denied, even though the directory is otherwise writable by the same user. Use a plain directory name. - Chromium's CLI has no "screenshot sized to content" mode — it always
renders at the requested
--window-sizeand leaves trailing whitespace if the page is shorter. The script renders tall (1200×1600) and crops the whitespace with a small PIL script (scans for the last row containing dark pixels). This needspython3-pilinstalled (sudo apt-get install -y python3-pil, one-time system package — not a per-run dependency, and not bundled with the base box image). - dbus/AppArmor
ERRORlines in stderr during the render (ListActivatableNames,UPower) are cosmetic sandbox noise, not failures — ignore them; only a missing output file means the render actually failed.
Uploading and posting
Upload goes straight to the media API (POST https://media.pollinations.ai/upload,
bearer $POLLI_TOKEN, multipart file field) rather than shelling out to the
polli CLI — the CLI isn't installed on the community-monitor box, and the
upload is a two-line fetch, not worth adding a dependency for. See
packages/polli-cli/src/commands/upload.ts if the media API response shape
ever changes.
The generator's stdout JSON includes a ready-to-post markdown field — the
CYCLE.md daily duty posts it verbatim as a single Discord message (the image
URL is inline in the text, Discord auto-embeds it). Don't re-derive or
paraphrase the markdown; the awards it calls out (workhorse by request
count, flawless-100% count, speed crown) are deliberately chosen to surface
stats the image itself doesn't show.
Companion design: "The Arena"
A second visualization (speed × success × price, avatar markers sized
uniformly, price tag per model) was explored alongside the main leaderboard
and posted once as a one-off — its HTML/build script live only in session
scratchpads, not yet promoted into this directory. If asked to make it a
recurring post too, port design-arena-v2.html's structure (GitHub avatar
thumbnails via https://github.com/<user>.png?size=96, pixelated via
nearest-neighbor resize, log-scaled x-axis, piecewise y-axis for the
95–100% success cluster, a simple pairwise-repulsion layout pass so
same-size markers don't overlap) following the same rendering/upload
pipeline as the main board.
Version History
-
8303332
Current 2026-08-20 04:57
重构:将 operations 目录迁移至仓库根目录,并重命名 CPU 基础设施文件夹。
- 99bce92 2026-07-25 10:38


