Field

The Line Outside — Two Screens Looking at One Queue

Managing a queue means two people in two places looking at the same line. The moment the door and the counter each start remembering their own number, an argument with a customer follows. We built two screens, called one party from the counter, and re-photographed the door screen nobody had touched.

By makemind · Aug 7, 2026

There is a tablet outside the restaurant door and another inside at the counter. Both look at the same line.

That is harder than it sounds. The person at the door writes customers in; the person at the counter calls the next party. The moment the two screens each start remembering "four parties right now", the counter seats one and the door still says four. And that mismatch shows up as an argument with a customer. A good part of what companies selling queue tools by monthly subscription actually sell is preventing that mismatch.

We built it with one server and two screens.

At the door

The door screen — HANOK TABLE · Front door. WAITING NOW 4 parties, 11 people, about 36 min to the next table, with the queue from #41 Han (next) to #44 Kwon (3 ahead)
The door screen — HANOK TABLE · Front door. WAITING NOW 4 parties, 11 people, about 36 min to the next table, with the queue from #41 Han (next) to #44 Kwon (3 ahead)

One big number, one estimate, a list. That is everything the door screen does.

The "next", "1 ahead", "2 ahead" in the list are not stored. Where you are in the line comes out of the list's order.

// Position is derived from the list order. Nothing stores
// "you are third" — that would be wrong the moment somebody
// ahead gives up and leaves.
'ahead': i == 0 ? 'next' : '$i ahead',

If a party ahead gives up and leaves, the ones behind move up a place automatically. Had it been stored, somebody would have to rewrite all of it.

At the counter

The counter screen — the same four parties with how long each has waited (20/14/7/0 min), NEXT UP `#41 Han (2)` on the right, and a button that carries that party
The counter screen — the same four parties with how long each has waited (20/14/7/0 min), NEXT UP #41 Han (2) on the right, and a button that carries that party

The counter screen sees the same line differently. It is not for showing customers, so how long each party has waited is attached.

counter sees the same 4 parties, front of the line has waited 20 min

the same 4 parties — that line is half this article. Both screens asked the server separately and got the same answer.

Calling

Press the button at the counter and the party at the front is seated.

Right after Han is seated — three waiting, NEXT UP moves to `#42 Oduya (4)`, and THIS SHIFT reads seated 1, average wait 20 min, quoted now 27 min
Right after Han is seated — three waiting, NEXT UP moves to #42 Oduya (4), and THIS SHIFT reads seated 1, average wait 20 min, quoted now 27 min

Two things happen at once here. They leave the list and stay in the record.

// The party leaves the waiting list but not the record. An owner who
// wants to know how long people actually waited has to be able to ask
// afterwards, and a deleted row cannot answer.
p.calledAtNote = 'waited ${_now - p.joinedAtMinute} min';
_served.add(p);

seated today: 1 — Han waited 20 min at the bottom of the screen is that record. It is exactly what is needed the moment the owner asks "what is our average wait", and a deleted row cannot answer.

And the door, which nobody touched

The door screen at the same moment — WAITING NOW 3 parties, 9 people, about 27 min. Nobody touched this screen
The door screen at the same moment — WAITING NOW 3 parties, 9 people, about 27 min. Nobody touched this screen

Nobody touched this screen. One button was pressed at the counter.

door reads: 4 parties, 11 people, about 36 min
counter called: called Han (41) — Han waited 20 min
door now reads: 3 parties, about 27 min — nobody edited this screen
estimate 36 min -> 27 min because the list is 4 -> 3

36 minutes became 27 not because somebody typed 27. The list went from four to three, and the estimate is computed from the list.

// The estimate the person at the door reads out loud.
'estimate': '${_waiting.length * _minutesPerTable} min',

_minutesPerTable is 9. It is a number the owner might change once in their life, and so that number alone sits in one place.

This content requires Developer or above

Sign in and upgrade your plan to continue reading.

View Plans
Twitter