Games leaderboard domain — data schema, scoring, game JSON format, visual tier rules, statistics visualizations, financials section, and backlog section for deepnimma.com
This skill triggers when editing these files:
src/sections/pages/games.tsxpublic/games/*.jsonpublic/games/backlog.jsonsrc/data/schema.jsonKeywords: games, leaderboard, scoring, letter grade, ComputedGame, schema categories, GameVisualizations, recharts, backlog, BacklogEntry, GameFinancials, price_paid, hours_played
You are working on the games leaderboard — a ranked, sortable list of played video games with weighted scoring, tiered visual styling, statistics visualizations, financials section, and a backlog section.
src/sections/pages/games.tsx — all UI, scoring logic, types, and visualizations (single-file, no imports from elsewhere except recharts)public/games/{n}-{slug}.json — one file per scored game; n is display order, slug is the id fieldpublic/games/index.json — auto-generated list of IDs; regenerated by /npm startnpm run buildpublic/games/backlog.json — hand-edited flat array of BacklogEntry objects; order = display rank; fetched at /games/backlog.jsonsrc/data/schema.json — categories, subcriteria, grade brackets; imported statically at module loadsrc/css/pages/Games.css — all styles for this feature"Completed" | "Playing" | "Dropped" | "Backlog" — "In Progress" no longer existsplayed_day field: optional integer on GameData; used by formatDate() and computeGapDays() for precisionformatDate(month, year, day?): helper that renders "Jan 5, 2024" (with day) or "Jan 2024" (without); used everywhere dates appear.toFixed(2) on both raw score and percentage (was integer)humanDays(days): formats gap as Nd / Nw / Nmo / Ny; toggled by "show days" button to show raw d countcomputeGame): sum subcriteria scores (or use score field if no subcriteria), divide by totalMax, multiply by 100 → weighted_percentagepuzzles is special: uses a flat score field (not subcriteria), supports enabled: false to exclude from totalschema.json → grade_brackets (sorted descending), S+ (≥97%) to F (≥0%)weighted_percentage > 98.5game-card-outer--playing dims playing-status cardsprice_paid / hours_played: optional fields on GameData; computeGame derives price_per_hour (stored in _computed) when both are present and hours_played > 0formatPrice(n) → "$N.NN"; formatHours(n) → "N.NNh"GameVisualizations)humanDays() by default, toggle to raw days"Playing" games for release timelineheatColor() maps pct → backgroundTOOLTIP_STYLE constant defines shared dark-theme tooltip stylingGameFinancials)GameVisualizations when any game has price_paid or hours_playedbuildPphScoreData(); requires ≥2 data pointsbuildHoursData(); bars colored by gradebuildSpendByPlatformData()buildCostScoreData(); requires ≥2 data pointsbuildHoursPerGradeData(); bars colored by grade.game-financials-inline (collapsed card row), .game-financials-row (expanded card row), .game-fin-block, .game-fin-stat, .game-fin-stat--pph (blue tint), .game-fin-sephours_played, price_paid, price_per_hour-1)public/games/backlog.json (flat array, not a directory)BacklogEntry type: { title: string; icon: string | null; release_month?: string | null; release_year: number | null }BacklogCard shows rank (array index + 1), icon/placeholder, title, and release year (or "TBD")BacklogStats shows total count, oldest/newest by release year, unknown-year count, per-year breakdown pillsbacklog.json (no priority field)index.json manually — regenerated on next start/build.public/games/backlog.json as array elements, NOT in public/games/ as individual files."Completed", "Playing", "Dropped", or "Backlog".computeGame affects all grades retroactively — verify against existing games before changing.buildRadarData skips puzzles (cat.key !== "puzzles") — update this filter if adding other opt-out categories..claude/guidelines/games-leaderboard/patterns.mdLast Updated: 2026-04-11