VulCode

RimShot

A humor platform where content fights in pairs: the user sees two memes, gifs or jokes from the same category and picks the funnier one. Every category has its own Elo ranking, and next to it an official ranking that loses 20 percent of its points every day, so an old hit does not sit at the top forever. Invites, reports with automatic hiding and a moderation queue control what reaches the vote.

TypeUser-generated content platform
FrontendReact 19, TypeScript, Vite
BackendExpress, TypeScript, Prisma
DatabaseSQLite
RankingElo in every category
RimShot

Overview

RimShot is a platform where people upload funny things, memes, gifs, pictures and jokes, and duels decide what is funniest. There are no stars and no likes. The user gets two pieces of content from the same category, picks the funnier one, and the winner gains points at the loser's expense, just like in a chess rating.

The name comes from the drum hit that lands after a punchline. Every duel ends with exactly that kind of verdict: this joke landed, that one did not.

Why duels and not stars

A star rating says more about the rater than about the content: one person gives fives to everything, another never does. Likes reward whatever the most people have seen, so an old hit keeps growing forever, and a fresh meme disappears before anyone sees it.

Comparing two things side by side is simpler and fairer. Nothing has to be calibrated, nobody has to wonder whether something deserves three stars or four, it is enough to point at which of two things is funnier. Many such simple decisions add up to a ranking that no single vote can rig.

Elo in every category separately

Every piece of content has an Elo rating only within its own category, because the humour of a gif cannot be sensibly compared with the humour of a one-line joke. A duel's result moves both ratings by as much as it was unexpected: beating a favourite earns a lot, beating a weaker opponent very little.

New content has a higher K-factor, so it quickly reaches the neighbourhood of where it belongs. Once it has collected enough comparisons the factor drops, the score settles, and a single viral evening does not lift it to the top for good.

elo.ts · ts
const PROVISIONAL_VOTES = 30;
const PROVISIONAL_K = 40;
const STABLE_K = 18;

export function kFactor(votesCount: number): number {
  return votesCount < PROVISIONAL_VOTES ? PROVISIONAL_K : STABLE_K;
}

export function expectedScore(ratingSelf: number, ratingOpponent: number): number {
  return 1 / (1 + 10 ** ((ratingOpponent - ratingSelf) / 400));
}

export function applyEloUpdate(eloA: number, votesA: number, eloB: number, votesB: number, winner: 'A' | 'B') {
  const expectedA = expectedScore(eloA, eloB);
  const expectedB = 1 - expectedA;
  const scoreA = winner === 'A' ? 1 : 0;
  const scoreB = 1 - scoreA;
  const deltaA = kFactor(votesA) * (scoreA - expectedA);
  const deltaB = kFactor(votesB) * (scoreB - expectedB);
  return { deltaA, deltaB, newEloA: eloA + deltaA, newEloB: eloB + deltaB };
}

Pairing that gives new content a chance

If pairs were drawn completely at random, new content would wait a long time for its first comparisons, and duels between the bottom and the top of the ranking would settle nothing and bore the voter. So pairing uses two weights.

The first item

content with few comparisons is drawn more often until it has collected enough.

The opponent

from the same category, picked more readily the closer its score is.

The vote

the user points at the funnier one, and both sides get their new score in one transaction.

The result is duels that actually decide something, and new content with a real chance of leaving its starting point.

Two rankings: all-time and official

The all-time ranking is pure Elo that never decays: an honest history of what was funniest. Next to it runs an official ranking with its own score. Every duel adds to the winner and takes from the loser as much as the Elo moved, the score cannot drop below zero, and every day at midnight all scores lose 20 percent. A hit from a month ago does not sit at the top forever, and first place goes to what is funny now.

Keeping the two numbers apart is deliberate. Squeezing Elo itself every day would stop it meaning what it means, because the expected result of a duel assumes both sides have stable ratings. A separate score makes it possible to have an honest history and a fresh ranking at the same time.

The two rankings side by side

RankingHow it works
All-timeElo within the category, never decays
Officialpoints from duels, minus 20 percent every day, never below zero

Fair voting and moderation

Uploading needs an account, and sign-up goes through an invite code and a captcha. Every member can generate invites for more people, so the community grows through people who are already in it. Uploads per day and votes per minute are limited, nobody can vote in a duel that includes their own content, and both items must come from the same category. The address a vote came from is stored only as a hash, for abuse detection.

Any piece of content can be reported with a reason. After a few reports it drops out of the voting pool by itself, but it is not deleted: it waits in the moderation queue, where an administrator restores or removes it. In the same panel the administrator adds categories, sets their content type and order, and switches them off without changing any code.

What the finished product actually delivers

The user gets a simple, addictive loop: two things, one click, the next pair. A creator sees how their meme does in a fair ranking, where what counts is what makes people laugh, not who posted first.

From the start the platform has what public uploads require: accounts, limits, protection against inflating your own scores, reports and a moderation queue. The official ranking stays fresh, and the all-time ranking remembers everything that ever won.

Questions about RimShot

More projects

More work from the same category - see how we tackle similar challenges.

Have a similar project?

Get in touch - a quote is free and comes back within an hour.