Skip to content

Open Algorithms & Code

Every algorithm that shapes your experience is documented here — in plain language, with the actual formulas, and direct links to the source code.

When an algorithm decides who sees your profile, how your reliability is scored, or which sessions appear in your feed — those decisions affect real-world interactions. A late-cancel penalty isn't just a number; it's the difference between a full table and a canceled game night.

We believe you deserve to understand how every scoring and matching system works. Not in vague marketing terms — in actual math, with the real weights, thresholds, and design tradeoffs explained.

Each section below documents one of our algorithm systems. You'll find the formula, the reasoning behind key decisions, and a direct link to the source code on GitHub. If something seems wrong, you can open an issue.

Player Reliability Score

The Player Reliability Score is an attendance-based metric that reflects your actual track record at game tables — not your popularity, not your social connections, just whether you show up when you say you will.

How It Works

Score = (weighted_sum / game_count) × 100

Clamped to range [0%, 100%]

Attendance status weights
Status Player Weight Host Weight
Attended +1.0 +1.0
Late Cancel (<24h) −0.3 −1.2
No-show −1.0 −1.5
Excused 0.0 0.0
Cancelled Early (>24h) 0.0 0.0

Tier Classification

Reliable

≥ 95% and ≥ 5 games

Active

≥ 5 games (any score)

Newcomer

< 5 games

Design Decisions

  • Hosts face steeper penalties for late cancellations and no-shows because they affect every participant signed up for that game, not just themselves.
  • Grief resistance: attendance is settled by a weighted consensus of reports (see Attendance Resolution), so no single reporter can decide a status — a participation threshold and a majority must agree before any penalty applies.
  • Scores are fully recomputed on every attendance change (not delta-based) to guarantee correctness and prevent drift.

Attendance Resolution

When a game ends, the host and participants can each file an attendance report for the same player — and they don't always agree. Attendance Resolution reconciles those reports into a single resolved status that feeds the Player Reliability Score. It is a consensus system with a deliberate default-to-attended bias: an absence has to be proven by a majority, never assumed.

Resolution Methods

Early Consensus

Every approved participant files a report, so the status resolves as soon as the game completes — no waiting.

Timeout

If reporting stalls, the game auto-completes once the window closes and resolves each player from whatever was filed.

Manual

An administrator can resolve attendance directly when a dispute needs a human decision.

How a Status Is Decided

1
Participation gate

At least half of the other participants must file a report. Below that, the player defaults to Attended.

2
Host-excused override

If the host marks a player Excused, that wins — the host is authoritative for excuses only.

3
No-show majority

More than half of the weighted votes must be "no-show" for an absence to be recorded.

4
Default to Attended

Anything else — a tie, no reports, or a solo game — resolves as Attended.

Reports are accepted for 72 hours after a game ends; games auto-complete 12 hours after their scheduled end time.

Design Decisions

  • Default-to-attended: no single report can ever penalize a player. An absence requires a proven majority.
  • The host can excuse, but only the consensus can mark a no-show — host authority is deliberately limited.
  • Reports are weighted, so low-reliability reporters carry less influence. The exact abuse-defense thresholds are intentionally not published.

GM Ratings & Reviews

GM Ratings aggregate community feedback for game masters into an average score and review count. Only published reviews contribute to the aggregate — reported or hidden reviews are excluded entirely.

How It Works

Average Rating = COALESCE(AVG(rating), 0)

Review Count = COUNT(*) WHERE status = 'published'

Proficiency Badges = TOP 3 tags by frequency across published reviews

Only reviews with status "published" are included. Reviews that are reported or hidden are excluded from all calculations.

Design Decisions

  • Only published reviews count toward the average. Reported or hidden reviews are excluded to prevent manipulation and ensure fairness.
  • Aggregates are recomputed when a review is created or deleted, and whenever a review changes status (for example, when a reported review is hidden or restored). This keeps the displayed score in sync with the current published set.

People Discovery

People Discovery suggests nearby players based on taste compatibility and social overlap. It uses your game system preferences, vibe preferences, team memberships, and social connections to find people you'd enjoy playing with. Results are precomputed by a background job and served from cache for fast page loads.

Pipeline

1
Phase 1: Geohash Tile Expansion

Runs a single query across the 4-character geohash tile (~20km) and the surrounding 3-character tile (~100km) at once, so city and regional neighbors are covered together. Blocked users and existing follows are excluded via a SQL subquery. The geographic candidate pool is capped at 50 to keep memory bounded.

2
Phase 2: Taste-Based Supplement

If the viewer has favorite game systems, additional candidates who share those preferences are pulled in — even outside the geographic radius — ensuring taste affinity is represented.

3
Phase 3: SQL-First Scoring

A single SQL JOIN query computes all overlap counts (shared game systems, shared vibes, shared teams, mutual follows) server-side, avoiding bulk PHP loading. The database returns at most 100 scored rows.

4
Phase 4: Scoring

Computes taste similarity (Jaccard on game systems + vibes) and social overlap (team overlap + mutual follows). Results are privacy-aware: hidden fields reduce available signals.

5
Phase 5: Cached & Paginated Results

Results are precomputed by a background job and cached per viewer per geohash tile for 5 minutes. The page reads from cache only — if the cache is cold, a "still looking" state is shown while the job runs. Paginated at 12 per page.

How It Works

Taste: J(A, B) = |A ∩ B| / |A ∪ B|

  Computed on game systems + vibes, averaged

Social: (team overlap + mutual follow) / components

Composite:

  if taste & social: score = taste × 0.7 + social × 0.3

  if taste only: score = taste

  if social only: score = social

Scoring component weights
Component Weight (both available)
Taste similarity 0.7
Social overlap 0.3

When only one signal type is available, it receives 100% weight.

Design Decisions

  • Privacy-aware reweighting: when a candidate has hidden fields (game systems, vibes, teams), those signals are excluded from scoring and remaining signals get proportionally more weight.
  • Blocked users are excluded from the candidate pool entirely — they never appear as discovery results.
  • When all signals are hidden (only location visible), the candidate appears with "Nearby" as the sole match reason, so the UI still shows something meaningful.

Session Recommendations

Session Recommendations suggest games and campaigns matched to your preferences. It uses a two-tier approach to surface the best matches first without penalizing users who haven't set vibe preferences.

Two-Query Approach

1
Boosted Query (Primary)

Matches sessions that share your favorite game systems AND favorite vibes. These are the strongest matches.

2
Fallback Query

Matches sessions by favorite game systems regardless of vibes. Surfaces relevant sessions even without vibe overlap.

Results are deduplicated by type+id, with boosted results shown first. Capped at 12 total recommendations.

Preference Resolution

allowed = (favorites + implied_favorites) − avoided

Boosted: allowed AND favorite_vibes

Fallback: allowed (any vibe)

Preference resolution rules
Rule Behavior
Base game favorited Expansions become implied_favorites
Explicit avoid Always wins over favorite or implied
Vibe exclusivity Favoriting one auto-avoids its partner

Design Decisions

  • Favorited base games automatically include their expansions as "implied favorites" — you don't have to favorite every expansion separately.
  • Explicit avoid preferences always win over favorite or implied — if you avoid a system, it stays excluded even if it's an expansion of a favorite.
  • Vibe mutual exclusivity: favoriting one vibe auto-avoids its partner (e.g., "Competitive" auto-avoids "Cooperative").

Gatherings

A Gathering is a lighter, multi-system session like a board-game night. In discovery feeds, gatherings are capped at roughly one per page and ranked just below focused single-system games on the same date, so they never crowd out specific games. In your recommendations, a gathering appears whenever any of its offered systems matches your favorites — treated like any other game.

Proximity Engine

The Proximity Engine powers geographic queries for finding nearby sessions, players, and venue hubs. It uses a two-phase approach: a fast bounding-box filter followed by precise Haversine distance calculation.

Two-Phase Approach

1
Phase 1: Bounding Box Pre-filter

Uses a composite (latitude, longitude) B-tree index for fast row elimination. The box is the smallest rectangle that contains the search circle — its corners reach past the circle, so nothing is missed.

2
Phase 2: Haversine Distance

Applies the Haversine formula for precise distance calculation, filtering results to the exact radius.

How It Works

d = 2R × arcsin(√(

  sin²(Δlat / 2) +

  cos(lat₁) × cos(lat₂) × sin²(Δlng / 2)

))

where R = 6371 km (Earth's radius)

Geohash Tile Sizes

Geohash precision levels and approximate tile sizes
Precision Approximate Size Use
4 chars ~20km × 20km City-level caching
5 chars ~4.9km × 4.9km Neighborhood-level
6 chars ~0.6km × 1.2km Venue-level

Hub results are cached per geohash tile (5-char ≈ 4.9km × 4.9km) with a 15-minute TTL.

Design Decisions

  • The bounding box is the minimal rectangle enclosing the search circle (its corners extend past the circle). The Haversine formula then filters to the precise radius — this two-phase approach uses the B-tree index for speed.

Location Disclosure & Privacy

Every address and distance you see — on a game, campaign, or venue page — is decided by a single service. Location Disclosure graduates how much of a location is revealed based on the nature of the place and your relationship to the host. Privacy is the default, not the exception.

Address Rungs

Exact

Full street address

City

Locality name only

Area

“In your area” (geohash-tile based)

None

Nothing shown (blocked viewer or unresolvable location)

Decision Matrix (private locations)

Your relationship to the host Address shown
Owner or approved participant Exact
Friend or teammate City
Stranger or guest Area
Blocked None

Verified commercial venues (cafés, game stores, libraries, community centers, conventions, bars) show their exact address to everyone — they are public spaces.

Distance Display

Verified commercial venue

Precise distance (e.g. “4.2 km away”)

Any other location

Grid-snapped to the nearest 5 km (e.g. “≈ 5 km away”), with a 5 km floor — exact positions cannot be triangulated.

Design Decisions

  • Fail-closed: if anything can't be determined, the service reveals the least it can (Area, or nothing) — never more.
  • Precise distances are reserved for verified public venues. Private locations always get a grid-snapped distance to prevent triangulation.
  • A public venue page requires a commercial type that is verified or admin-managed. “Other” and untyped locations never qualify.

Platform Score

The Platform Score ranks game systems by community engagement using a weighted formula that accounts for favorites, total games, campaigns, and active (scheduled) sessions.

How It Works

score = (favorites × w₁) + (games × w₂)

      + (campaigns × w₃) + (active_games × w₄)

Type-differentiated scoring weights
Signal Board Games TTRPGs
Favorites 10 10
Total Games 3 3
Campaigns 5 15
Active Games (scheduled) 20 10

Design Decisions

  • Board games weight active sessions highest (20 pts) because a currently-scheduled game is the strongest signal of community engagement.
  • TTRPGs weight campaigns highest (15 pts) because ongoing campaign play is the primary activity metric for tabletop roleplaying groups.

Read the Code Yourself

Every algorithm documented here runs from our open-source repository. Clone it, audit it, open an issue — it's all yours.

You're offline — some features may be unavailable
Back online