Design Google Meet's Participant Grid - Vinit Shahdeo

Design Google Meet's Participant Grid

Keeping participant tiles stable as people join and leave, from the core data structure to scaling for thousands.

Vinit Shahdeo
Jun 22, 2026

I’ve asked this question in interviews a lot, and it’s still my favorite.

When people hear “video conferencing app,” they reach for the big stuff: databases, queues, services calling each other. You don’t need any of that. Most of this problem is just picking the right data structure. There’s a system design part too, but it only shows up if you keep going, so I’ve put it at the end. Let’s start with the core.

Here’s the question:

Design the participant layout for a video conferencing app like Google Meet. People join and leave at any time. Show everyone in a grid.

One thing to clear up first, because someone always brings it up. Real apps like Meet and Zoom don’t show a plain grid. They deal with the active speaker, pinned people, screen sharing, and so on, and they don’t move tiles around the way I’m about to describe. For this question, just assume everyone has equal priority, and the only goal is to keep tiles from jumping around. That version is the interesting one.

Understand the problem first

Spend a minute here. Half the people I talk to skip this and wish they hadn’t.

What does it need to do?

And the one rule that makes it hard:

If you’ve been on a call where everyone slides over the second someone joins, you know why this matters. That one rule is basically the whole problem.

The first answer almost everyone gives

Nine out of ten people start here:

“Keep everyone in a list, sort by name or join time, and draw the grid from that.”

It looks fine with three people. So I ask:

“What happens when the second person leaves?”

And it breaks:

Either way, tiles jump. The problem isn’t the architecture. It’s that the data structure is wrong for the rule we set. Sorting rebuilds the whole layout from scratch every time anything changes, and a video call is nothing but a change.

The key insight: name the rule first

Every problem like this has one rule that everything hangs on. Here it is:

Tiles that are already on screen shouldn’t move.

Once you say that out loud, the data structure picks itself. A sorted list breaks the rule on purpose, because it works out every position again on every change. So don’t sort.

Instead, give each person a seat when they show up: the next open seat, at the end. That seat is theirs. When someone new joins, a tile appears at the end, and nobody else moves.

The leave is the real question

Joins are easy. Leaves are where it gets interesting.

Say the grid is A(0) B(1) C(2) D(3) and B leaves from the middle. You have three choices:

The third one is the answer, and it’s not a toss-up. If you want the grid to stay full after someone leaves from the middle, something has to move. You can’t fill a hole without moving at least one tile, and moving the last person is the smallest move you can make. It’s the old swap-with-last trick.

When someone gets here on their own, I know the rest of the conversation is going to be good.

The data structure

Since you always fill gaps from the end, you never build up holes, so the whole thing stays small. An array and one map:

const order  = [];          // index = seat, value = person
const seatOf = new Map();   // person -> seat index

function join(person) {
  seatOf.set(person, order.length);
  order.push(person);            // new tile at the end; nobody moves
}

function leave(person) {
  const i = seatOf.get(person);
  seatOf.delete(person);
  const last = order.pop();      // the person in the last seat
  if (i < order.length) {        // the leaver wasn't already last
    order[i] = last;             // move them into the gap
    seatOf.set(last, i);         // one tile moves
  }
}

Both join and leave are O(1). That’s the core.

Putting it together

What I’m listening for

And the follow-up I always ask:

“Someone in the middle leaves. What happens to everyone else?”

Three answers, three signals:

That’s the whole question, really. One idea, used well. If you can explain the seat trick to a friend in two minutes, you’ve got it.

Going further: the system design part

If the interview keeps going, this is where the small problem turns into a system. Three things come up, more or less in this order. The seat idea doesn’t change. This is all built around it.

1. Everyone has to agree on the order. Seat assignment depends on the order in which things happen. Append-on-join and move-the-last-on-leave yield different results if two machines observe the joins and leaves in a different order. So you can’t let every client work out their own seats; they’d disagree. You need one referee. One server per meeting hands out seats and tells everyone. That’s your single source of truth. It’s cheap, because joins and leaves don’t happen often. Even a 1,000-person meeting has only a few per second. The heavy traffic is the video itself, handled by a separate part of the system (the SFU). Working out seat order is tiny next to that, and you’d never put it in the video path.

2. Keeping everyone in sync. Send the full picture once, then small updates after that. Same idea as video: one keyframe, then diffs. When you join, the server sends the full seat map. After that, it sends small updates with a number on each one: “Vinit joined at seat 7,” “Vaibhaw moved from seat 12 to seat 3.” The rule on the client is to apply them strictly in order: skip anything you’ve already seen, ask for a fresh snapshot if you spot a gap, and otherwise apply the next one. That makes repeats and out-of-order messages harmless.

// Update #42: move Vaibhaw from seat 12 to seat 3

if (update.version <= appliedVersion) return;     // dup or stale, ignore it
if (update.version > appliedVersion + 1) {        // gap, we missed one
  requestSnapshot();                              // resync instead of guessing
  return;
}
apply(update);                                    // exactly the next one
appliedVersion = update.version;

And if the network drops, don’t blank the screen. Keep showing the last layout, reconnect, then fix only what changed.

3. Scaling to thousands. You can’t draw 3,000 tiles or pull 3,000 video streams. So show one page at a time, around 50 tiles, and only pull video for the people on that page, plus the speaker and anyone you’ve pinned. The seat map can hold thousands of people in memory cheaply. You just draw a small slice of it.

This keeps leaves cheap, but be clear about why. A leave changes exactly one seat: the gap gets the last person, and the very last seat goes away. So on whatever page you’re looking at, at most one tile changes. A new face shows up in the gap, and everyone else stays put. The person who got moved was probably on another page anyway, so it feels like a new face showing up, not the grid shuffling. Most of what you see stays still, because only one seat ever changes.

A quick note on “thousands”: one server can hand out seats, but it can’t carry all the video. At that size, the media is spread across several SFUs that work together (cascading), and most people are view-only. None of that touches the seat logic, though. The layout side stays the same.

No matter how big the meeting gets, you’re drawing around 50 and pulling around 50.

The question I save for the best people

Once someone has all of it, I ask one more:

“What if we wanted nothing on screen to move at all, not even the one tile?”

There’s no single clean answer, which is why I like it. It opens up a bunch of options: leave the holes and live with them; only tidy up the grid every so often, in a batch, so movement is rare; keep seat numbers separate from the actual screen spots; give each tile a fixed ID so it slides into place instead of snapping; or only tidy up the part of the grid you can actually see. Listening to someone think through those trade-offs is what tells me good from great.

That’s why I keep asking it. Take away the video call, and the real lesson is the part I care about: figure out the one rule first, then pick the data structure that keeps it with the least work. Here, the rule was “don’t move tiles,” and once you name it, an array and a swap-with-last do the whole job. No fancy algorithms. The core shows me how someone thinks. The scaling part shows me how far they can go.

If you liked this, you'll probably like another question I keep asking in interviews. 99% of people fail to answer it: Re-Hash Facebook’s Passwords **.