Scope Creep Files: A Bar Chart Worth Sharing

Today I want to tell you about how I started with a simple bar chart and ended up building something much more complex. This happens to me a lot - I start with a basic idea and then keep discovering new requirements.

This isn't a story about professional software development. There's no business value, product manager, no maintenance planning, lighter accessibility requirements - just me, tinkering with code for fun.

Table of Contents

Skip to the final demo

If you just want to see the final visualization (hi mom ❤️), then jump to the end. You don't have to read a few thousand word tour of my design process →

Why

In this case my design goal was transforming a bunch of statistical analysis work (no boring details I promise) into something worth sharing with friends. I knew I couldn't simply show them a table of numbers and have them think kindly of my verbal explanation - I needed to make it engaging and fun. Therefore in this post I will keep adding features until we have something that feels worth sharing.

Ideally my mom can look at the final output and say "wow, that's neat." without understanding the underlying math that so fascinates me. That's the goal.

The starting point: a basic bar chart

I began with a standard horizontal bar chart from an open source component library. It had clean proportions and nice colors. Each bar showed a single value with a right-aligned label. Pretty straightforward.

65.0

Adding live updates

But then I thought: "This chart needs to show live data from an ongoing game." Instead of static values, the bars would need to update as players made moves and scores changed.

This led to an interesting question: How do we help viewers understand that values are changing? We could add text saying "Updated!" but that feels clunky. What we really want is to show the change visually.

Imagine an lame "Updated!" popup modal animation on top of the previous bar chart demo component

Learning from other visualizations

I thought about how other tools show changes in values. When tracking changes in values over time, the financial world offers us a helpful visualization pattern. Let's look at something called a candlestick chart - a tool traders use to show how prices move throughout the day.

Imagine an candlestick chart GIF here

In a candlestick chart, each price change gets a colored block: green when the price goes up, red when it falls. These blocks stack from right to left like a timeline, making it easy to see the history of changes. The height of each block shows exactly how big the change was.

This visual language of colored blocks to show change is powerful - it lets you instantly understand not just that something changed, but by how much. This seemed like a good pattern to borrow for our bar chart:

This way, viewers don't just see the current values - they can actually see the change happen. When a player's score jumps from 100 to 150, you'll see a green block showing that +50 increase. If another player drops from 200 to 175, a red block will show that -25 decrease.

While candlestick charts excel at showing historical patterns, our needs are simpler. We want to show multiple players' scores side by side and make score changes immediately obvious. So we'll skip the historical view and focus on the immediate change. When a score updates, we'll briefly show a colored bar section for the amount it changed, then fade that section away to reveal the new score. This gives us a clean bar chart that comes alive with each score update.

Imagine an animation demo

For the careful reader: Yes, I need to be careful with red and green for colorblind users. Yes, there are some locales where red and green have different cultural meanings. I'm aware of these issues.

TODO somehow say that I can skip these considerations because the target audience is 3 people.

The alignment puzzle

Once I decided to show these delta animations, I had to figure out where to put the numbers. Should they:

I settled on right-aligned numbers with a delta indicator: "77.0 (-5)". This kept things clean while showing both the current value and recent change.

Time: 0ms
30.0

The real data arrives

Then I looked at the actual data I needed to display: Bradley-Terry model scores. This introduced a whole new wrinkle - the values could be shown in two different ways:

  1. Log odds centered around zero (positive and negative values)
  2. Betting strengths (always positive, from 0 to ~600)
Imagine a picture of a scatter plot

This meant the bars might need to extend both left and right from a center point. The whole right-aligned number scheme suddenly got more complicated.

Imagine a demo of centered bar chart showing positive and negative values

Handling negative values

With bi-directional bars, the standard approach is to put numbers at the end of each bar. This meant:

Now the delta animations needed to handle crossing zero - a big jump from +82 to -5 needs to show the full range of change while still ending up with a properly aligned negative value.

Imagine a demo of zero crossing animation

The mobile context

Finally, I realized these charts would be shown in a scrolling list on phones. Users would see 2-3 charts at once, each showing different judges' scores for the same item.

This raised a new question: Should each chart use its own scale to maximize the visible differences, or should they share a consistent scale for easier comparison? The solution: Add a toggle between "global scale" and "zoom to fit".

Imagine a demo of controls for toggling scales here

Requirements then and now

Original requirements:

Final requirements:

This is what I mean by scope creep - each new requirement made sense, but they sure added up!

Imagine the Final Demo here

Discussion: When Your Goal is "Wow"

I felt kind of guilty while building this. Years of product development have trained me to be deeply suspicious of scope creep. "Start with MVP!" my brain keeps saying. "Ship early, ship often!"

But here's the thing - I'm not really solving a business problem. I'm trying to show my friends something cool. And that changes everything about how we should think about incremental development.

Let's be honest about the social dynamics at play here. No one inherently cares about Bradley-Terry models or visualizing the mathematical elegance of system evolution as more things are compared head-to-head. That's my interest, not theirs. If I want to share this with friends, I need to transform it into something that provides value for them.

What I can offer is a moment of entertainment - a brief "wow, that's neat" that makes sharing my interest worth their time. Showing them a table of numbers and promising "it'll get cooler next week" isn't just ineffective - it's actually inconsiderate. It asks them to invest attention in something that isn't yet worth their time.

The scope creep here isn't feature bloat - it's the minimum work required to transform "thing I find interesting" into "thing worth showing to other people." All those careful animations and polished interactions? That's the gift wrapping that makes my weird interest socially acceptable to share.

This makes me think differently about scope creep. We talk about it like it's always bad - a failure of discipline or focus. But sometimes what looks like scope creep is actually the process of discovering what's necessary for your real goal.

In this case, my goal was "build something I can share without being that guy who won't shut up about his pet project." And you can't really MVP your way to that. You have to do the work to make it engaging.

That said, I still feel weirdly guilty about it. Like I'm breaking some fundamental rule of software development. But maybe the real rule should be "understand your actual goals." Sometimes those goals don't fit neatly into our usual frameworks for thinking about product development.

The MVP framework is a tool for managing risk and learning about user needs. But when your goal is "transform my nerdy interest into something worth other people's attention," maybe it's okay to just build the whole thing.