Floor and rail
Tables by zone with guests, order state and a ready count, and a kitchen rail grouped by station with an age timer on every ticket.
Open it twice, take an order as a waiter in one window, and watch the ticket land on the kitchen rail in the other. Bump it and the table turns green back on the floor. Most people assume that needs a server. It needs one browser.
Opens kitchen.taiphamsolutions.com in a new tab. No account, no signup, and nothing you do in it leaves your browser.
The waiter window is the floor plan: tables by zone, open an order, add dishes, send to the kitchen. The kitchen window is the rail: tickets coloured by station with a running age timer, start and bump. The pass sits between the two, and a manager gets service statistics, the audit log, and an auto cook simulator that advances tickets on its own so one person can demonstrate the whole loop.
Every mutation goes through one function that writes the changed records to IndexedDB, applies them to local state, and broadcasts the records themselves. A receiving window applies the payload straight to memory and paints rather than reading the database again, because the database is per origin and the sending window has already persisted it. That is where the immediacy comes from, and the header prints the measured latency so the claim is checkable rather than asserted.
Concurrent edits resolve by last writer wins on a Lamport counter, with the writing window's id as a deterministic tiebreak, so every window lands on the same result rather than on its own. Mutations are serialised through a small queue, so a fast double tap raises a quantity instead of leaving two identical rows. An order's status is derived from its items and a table's from its order, so bumping the last item promotes the ticket and repaints the floor with no second message crossing the channel.
Open a second window from the lobby, pick Waiter in one and Kitchen in the other, and send an order. The peer list in the header prints the measured latency between them.
14 tables across three zones, 26 dishes in five categories routed to four stations, seven staff, and one dish already off the menu.
Tables by zone with guests, order state and a ready count, and a kitchen rail grouped by station with an age timer on every ticket.
A broadcast channel with a storage event as its fallback, and a peer list naming every open window, its role, and the latency measured to it.
Waiter, kitchen, expo and manager, held per window rather than per browser, so two windows open side by side do not fight over one role.
Service statistics, the audit log, a reset, and an auto cook simulator that advances tickets so the loop can be shown without a second person.
Every step below happens inside the demo. There is no point in it where the work leaves the browser and comes back.
A table on the floor plan takes a guest count and opens an order against it.
Dishes are added and sent. The records are written, applied locally and broadcast in the same step.
The other window paints the ticket without reading the database again, coloured by station, with its age timer already running.
Items are started and bumped. Bumping the last one promotes the ticket, because a ticket's status is derived from its items rather than stored beside them.
The table turns green with a ready count and a toast, from the same broadcast rather than from a message sent for the purpose.
Serving the ready items closes the loop and returns the table to free, which is where the next order begins.
There is no server behind any of this, which decides both columns. The left one is what that constraint made worth building properly. The right one is what it rules out.
The write-up sells harder than the application does, so it is on the page rather than in a repository nobody can open.
A demo exists to prove something on the offer list rather than to be impressive on its own. These are the ones this one argues for.
Each one is a different kind of problem, and all of them are in the Demos menu at the top of the page.
This one was built to a constraint nobody would choose. Yours would have a server, real accounts, and the parts of the domain that are actually hard. Tell us what the software has to do and we will tell you what it takes.
Bring the messy version of the problem. That is the conversation we enjoy most.