A Beli-inspired head-to-head ranking web app. Rank any collection of items using binary-search comparisons and flexible bucketing.
Live at: https://niconekoru.github.io/kRank/
- Binary-search comparisons: Efficiently rank items by comparing pairs
- Flexible bucketing: Assign items to 3 configurable buckets (liked/fine/disliked by default)
- Skip & Undo: Skip items for later decision and undo your last action
- Multiple universes: Keep separate ranked lists with isolated data
- Local-first: All data stored in browser localStorage; no backend required
- Export: Copy ordered leaderboard with scores to clipboard
- Responsive: Works on desktop and mobile
- Keyboard shortcuts: Arrow keys and number keys for fast decisions
# Clone and install dependencies
git clone https://github.com/NicoNekoru/kRank.git
cd kRank
bun install
# Start development server
bun run dev
# Build for production
bun run build
# Preview production build locally
bun run preview- Create a universe: Enter a name and paste your list of items (one per line)
- Bucket assignment: For each new item, decide which bucket it belongs to
- Head-to-head comparisons: The app presents a candidate item vs. an existing ranked item from the same bucket
- Binary search: Your choice narrows down the candidate's position using binary search
- Score calculation: Items are assigned scores based on their position within the bucket's range (0-10 scale)
- Leaderboard: View the final ranked order, rerank or remove items as needed
Buckets map to score ranges and can be customized in src/constants.ts:
| Bucket | Score Range | Color |
|---|---|---|
| liked | 7–10 | Green |
| fine | 4–6 | Yellow |
| disliked | 0–3 | Red |
Positions within the bucket are interpolated to produce granular scores.
| Action | Key(s) |
|---|---|
| Choose left | ← or 1 |
| Choose right | → or 2 |
| Skip current | s or Space |
| Undo | z or u |
| Edit items | e |
| Open help | ? or h |
src/
├── components/
│ ├── BucketSelect.tsx # Bucket assignment UI
│ ├── Compare.tsx # H2H comparison UI
│ ├── SkipUndoButtons.tsx # Skip/Undo controls
│ ├── ProgressBar.tsx # Ranking progress indicator
│ ├── Leaderboard.tsx # Final ranking display
│ ├── Landing.tsx # Universe list/creation
│ ├── Setup.tsx # Edit items view
│ └── HelpModal.tsx # Keyboard shortcuts help
├── store.ts # SolidJS store + actions
├── algorithm.ts # Binary search logic
├── constants.ts # Bucket definitions
├── types.ts # TypeScript interfaces
└── main.jsx # App entry point
Edit src/constants.ts:
export const BUCKETS = [
{ id: 'amazing', label: 'Amazing!', description: 'Top tier', range: [8, 10] },
{ id: 'good', label: 'Good', description: 'Solid choice', range: [5, 7] },
{ id: 'meh', label: 'Meh', description: 'Just okay', range: [2, 4] },
{ id: 'bad', label: 'Bad', description: 'Not for me', range: [0, 1] },
] as constThis project is configured for automatic deployment to GitHub Pages using GitHub Actions.
- Push to
masterbranch (ormain, update workflow if needed) - Go to Settings → Pages in your GitHub repo
- Set Source to GitHub Actions
- Workflow will build and deploy to
gh-pagesbranch
The site will be available at: https://<username>.github.io/<repo>/
bun run build
# Deploy the `dist/` folder to any static host- Framework: SolidJS (fine-grained reactivity)
- Build tool: Vite
- Runtime: Bun
- Styling: Vanilla CSS with CSS custom properties
- Storage:
localStoragefor persistence - CI/CD: GitHub Actions → GitHub Pages
- Data persists in browser localStorage; clearing site data erases all universes
- Works offline once loaded (PWA-capable)
- URL routing using
?universe=query parameter - No backend, no tracking, no cookies
MIT