The Chrome Extension Every Distracted MLB Fan Needs

1 day ago 3

0x676f64

I’ve been a software engineer for just over a decade now. About a year ago, I took on a new role that brought me out of my home office and back into a traditional workplace. As it turns out, the change was exactly what I needed.

While the new job has been a great experience overall, it did come with some trade-offs. Little things I used to enjoy — like taking an afternoon break to relax and catch an MLB day game — no longer fit so easily into my schedule.

Sometimes I have to remind myself that I can code

When Spring Training rolled around this past summer and I saw the schedule full of day games, I let out a sigh and chalked it up as one of those small sacrifices that come with a great opportunity.

But then I caught myself and thought, “Wait — you can code.” Sometimes I need that reminder.

So I decided to build something: a simple Chrome Extension that acts as an overlay, displaying the day’s MLB games, live results, standings, lineups, team stats, and player data. In short, a one-stop shop for baseball fans who love the game but don’t always have time to watch it live.

From Idea to Execution

With that thought in mind, I opened up my editor and started sketching out what this extension could look like. I wanted something lightweight, fast, and always available — something that wouldn’t interrupt my workflow but could keep me connected to the game. Over the next few weekends, I built out the core features and refined the UI. What started as a simple overlay quickly turned into a powerful little companion for baseball fans like myself.

I call it binBot, and some features include:

  • Real-time game updates and scores
  • Daily matchups and lineups with team logos
  • Player-level stats with percentile rankings
  • Team-level stats with percentile rankings for both batting and pitching
  • Dynamic design that adapts to new games
  • Minimal UI overlay so it doesn’t disrupt your workflow
Default homepage for current games
async function fetchGameDetails(gamePk) {
try {
const response = await fetch(`https://statsapi.mlb.com/api/v1.1/game/${gamePk}/feed/live`);
const data = await response.json();

if (data && data.liveData) {
const linescore = data.liveData.linescore;
const inningHalf = linescore.inningHalf ? (linescore.inningHalf === "Top" ? "TOP" : "BOT") : "";
const currentInning = linescore.currentInning || "";
return `${inningHalf} ${currentInning}`;
}
} catch (error) {
console.error("Error fetching game details:", error);
}
return "In Progress";
}

Pre-Game Lineup Cards, along with Probable Pitchers
if (gameState === "Pre-Game" || gameState === "Scheduled" || gameState === "Warmup") {
document.getElementById("scorebug-wrapper").style.display = "none";

// Display probable pitchers
if (data.gameData.probablePitchers) {
const awayPitcher = data.gameData.probablePitchers.away;
const homePitcher = data.gameData.probablePitchers.home;

Up to the second Results and Data for for Live Games
// Determine color based on event or description
if (pitchResult === "Strikeout" || pitchResult.includes("Called Strike") || pitchResult.includes("Swinging Strike")) {
pitchResult = pitchResult === "Strikeout" ? "Strikeout" : "Called Strike";
resultClass = "strike";
} else if (pitchResult.includes("Ball") || pitchResult.includes("Ball In the Dirt")) {
pitchResult = "Ball";
resultClass = "ball";
} else if (pitchResult.includes("Walk")) {
pitchResult = "Walk";
resultClass = "ball";
} else if (pitchResult.includes("Single") || pitchResult.includes("Double") ||
pitchResult.includes("Triple") || pitchResult.includes("Home Run")) {
pitchResult = lastPlay.result?.description || pitchDetails.details.description;
resultClass = "hit";

// Extract hit data if available
const hitData = pitchDetails.hitData;
if (hitData) {
const launchSpeed = hitData.launchSpeed ? `${hitData.launchSpeed.toFixed(1)} MPH` : "N/A";
const launchAngle = hitData.launchAngle ? `${hitData.launchAngle.toFixed(1)}°` : "N/A";
const totalDistance = hitData.totalDistance ? `${hitData.totalDistance} ft` : "N/A";

Current Team Stats, along with Percentiles
// Function to fetch team stats
async function fetchTeamStats() {
try {
// Fetch hitting stats for all teams
const hittingResponse = await fetch('https://statsapi.mlb.com/api/v1/teams/stats?season=2025&group=hitting&stats=season&sportId=1');
const hittingData = await hittingResponse.json();

// Fetch pitching stats for all teams
const pitchingResponse = await fetch('https://statsapi.mlb.com/api/v1/teams/stats?season=2025&group=pitching&stats=season&sportId=1');
const pitchingData = await pitchingResponse.json();

return { hitting: hittingData, pitching: pitchingData };
} catch (error) {
console.error('Error fetching team stats:', error);
return null;
}
}

Player searches, along with stats and Percentiles among qualified players
function getHittingStatConfig() {
return [
{ name: 'avg', display: 'Batting Avg', format: (v) => parseFloat(v).toFixed(3).replace(/^0+/, ''), goodHigh: true },
{ name: 'homeRuns', display: 'Home Runs', goodHigh: true },
{ name: 'rbi', display: 'RBI', goodHigh: true },
{ name: 'stolenBases', display: 'Stolen Bases', goodHigh: true },
{ name: 'obp', display: 'On-Base %', format: (v) => parseFloat(v).toFixed(3).replace(/^0+/, ''), goodHigh: true },
{ name: 'slg', display: 'Slugging %', format: (v) => parseFloat(v).toFixed(3).replace(/^0+/, ''), goodHigh: true },
{ name: 'ops', display: 'OPS', format: (v) => parseFloat(v).toFixed(3).replace(/^0+/, ''), goodHigh: true },
{ name: 'hits', display: 'Hits', goodHigh: true },
{ name: 'doubles', display: 'Doubles', goodHigh: true },
{ name: 'triples', display: 'Triples', goodHigh: true },
{ name: 'strikeOuts', display: 'Strike Outs', goodLow: true },
{ name: 'leftOnBase', display: 'Left On Base', goodLow: true },
{ name: 'baseOnBalls', display: 'Walks', goodHigh: true },
{ name: 'totalBases', display: 'Total Bases', goodHigh: true },
{ name: 'plateAppearances', display: 'Plate Appearances', goodHigh: true },
];
}
Read Entire Article