TreeMap
A free, open-source disk-space visualizer. Squarified treemap, duplicate hunting, disk-full forecasting, and cleanup that only ever moves files to the Trash.
翻译准备中
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证正在加载完整 README。 以下为已保存的摘录。
Rank anything by comparing two items at a time. Add text, images or colors, pick your favorite in each duel (buttons, keyboard or swipe), and let the ranking emerge. Live: https://versus.steevepommier.com/ (en français; the app itself is at /app/), also on https://costardrouge.github.io/versus/, without publishing查看完整 README ↗
Rank anything by comparing two items at a time. Add text, images or colors, pick your favorite in each duel (buttons, keyboard or swipe), and let the ranking emerge.
Live: https://versus.steevepommier.com/ (en français; the app itself is at /app/), also on https://costardrouge.github.io/versus/, without publishing
← A, → B, ↓ tie, S skip, ⌘/Ctrl+Z undo) or swipe.| Method | Algorithm | Best for |
|---|---|---|
| Balanced (default) | Bradley-Terry, fitted on all duels at once, with a ± margin per item | Photos, products, anything that doesn't change |
| Dynamic | Elo, duel by duel | Preferences that evolve over time |
| Simple | Smoothed win rate | Readability |
| Exact sort | Binary insertion sort | Settling a short list in the fewest duels |
llms.txt, all generated from one file (see docs/seo.md).docs/pwa.md).localStorage); only what you publish is sent. Visits are counted with a self-hosted, cookie-free Umami, never loaded for visitors who decline (a switch on the legal notice, Do Not Track, Global Privacy Control), and never with a ranking's content or id (see docs/analytics.md).docs/published-boards.md.docs/published-boards.md#notifications)./admin/ lists boards with their reports, hides or features them, removes items and takes boards down (see docs/published-boards.md#moderation)./t/<slug>/, /fr/t/<slug>/) listed in the sitemap once it has a crowd; the gallery's Popular section shows them with the boards the publisher put forward, to vote or start one's own ranking from.Requires Node.js 22 or newer; the project is developed and built on Node 26 (see .nvmrc).
npm install
npm run dev # local server with hot reload
npm run check # lint, typecheck, tests, build: what CI runs
| Script | What it does |
|---|---|
npm run dev | Vite dev server |
npm run build | Production build into dist/ |
npm run preview | Serve the production build |
npm test / npm run test:watch | Unit tests (Vitest) |
npm run coverage | Tests with coverage; the scoring engine must stay above 90% |
npm run e2e | End-to-end tests in Chromium (Playwright): duels by keyboard and swipe, the items list, the color editor, a published board voted to the end |
npm run lint / npm run format | Biome lint and format check / auto-fix |
npm run typecheck | TypeScript in strict mode (app and Worker) |
npm run worker:dev | The whole app and the published boards API on http://localhost:8787 (npm run dev proxies /api to it) |
npm run worker:deploy | Build, deploy to Cloudflare and apply the D1 migrations (needs a Cloudflare account) |
npm run icons | Redraw the favicons, app icons and social card into public/ from build/site.ts |
npm run screenshots | Take the install dialog's screenshots of the app into public/ (needs Playwright's Chromium: npx playwright install chromium, or CHROMIUM_PATH) |
npm run e2e | End-to-end tests: Playwright's Chromium against the app and the Worker run locally (npx playwright install chromium once, or CHROMIUM_PATH) |
npm run vapid | Print a key pair for notifications, to set as the Worker's secrets VAPID_PUBLIC_KEY and VAPID_PRIVATE_KEY |
src/
core/ pure, framework-free logic (fully unit tested)
scoring.ts Bradley-Terry, Elo, win rate, exact sort, pair selection
colors.ts hex/HSL conversions, gradients, harmonies
demos.ts demo data and deterministic simulation
board.ts published boards: votes, visibility, pair assignment
protocol.ts messages and views shared by the app and the Worker
i18n/ en.ts (source of keys), fr.ts (type-checked against en), helpers; landing-*.ts for the home page
landing/ the home page, rendered at build time in each language, then animated
admin/ the publisher's moderation page (/admin/), client of the Worker's admin routes
app/
ui.ts mount(): the entry point
gallery.ts, workspace.ts, items.ts, duel.ts, results.ts, color.ts one module per view
publish.ts, board.ts, remote.ts publishing, the published board page, the API client
rankings.ts navigation and actions on whole rankings
events.ts delegated event listeners
state.ts, dom.ts, header.ts, format.ts, storage.ts shared state, DOM helpers, header, formatting, localStorage
styles.css
build/ build-time SEO: site facts, head tags, JSON-LD, manifest, robots, sitemap, llms.txt (docs/seo.md)
scripts/ icons.ts: icons and social card
worker/ Cloudflare Worker: the site, the API, one Durable Object per published board
tests/ Vitest suites (core, jsdom views, the Worker in workerd) and Playwright end-to-end tests (tests/e2e)
worker/ serves the app and the API for shared boards: each published board is a Durable Object with its own SQLite storage and WebSockets, a D1 registry backs the admin API, and per-IP limits and Turnstile guard publishing. The rules live in src/core/board.ts, shared with the app. It runs locally (npm run worker:dev), in the tests, and live at versus.steevepommier.com; CI deploys it, see docs/online-architecture.md.
.github/workflows/ci.yml runs on every pull request and push to main: Biome, TypeScript, Vitest with coverage, a production build, and the Playwright end-to-end tests (the app with a faked API, and against the real Worker). On main, once both pass, the build is deployed to GitHub Pages, and the Worker (app + API) to Cloudflare once the repository has the CLOUDFLARE_ACCOUNT_ID variable and the CLOUDFLARE_API_TOKEN secret (setup). Dependabot keeps npm packages and actions up to date.
The Pages source must be set once to GitHub Actions in Settings → Pages.
CLAUDE.md: working memory for Claude Code (conventions, code map, domain rules).docs/decisions.md: decision log.docs/roadmap.md: done, next, later, open questions.docs/published-boards.md: agreed behavior of published (shared) boards.docs/online-architecture.md: backend for published boards on Cloudflare (worker/), and how to deploy it.The texts are typed against English, so TypeScript flags a missing key; the language lists are not, so each needs it:
src/i18n/fr.ts and translate it; register it in src/i18n/index.ts (LANGS, MESSAGES, PLURALS); add its button to the language switcher in app/index.html; add its labels to the demos (src/core/demos.ts).src/i18n/landing-*.ts and legal-*.ts, the page shells (copy fr/index.html and fr/mentions-legales/index.html), the language lists in src/landing/ (markup.ts, frame.ts, sections.ts) and src/legal/mount.ts.build/site.ts (LANGUAGES, the pages, titles, descriptions, social cards, LOCALES), then npm run icons for its social card.BoardLang in src/core/types.ts, its use in src/core/board.ts, the templates (src/core/templates.ts, TEMPLATE_LANGS), the Worker's texts (src/i18n/unfurl.ts) and routes (worker/src/index.ts, worker/src/templates.ts).src/i18n/admin.ts and src/admin/admin.ts.grep -rn "'fr'" src build worker/src lists the places that name a language.
MIT © 2026 Steeve Pommier