CHEF!'s first playable build is dated 13 September. By its sixth day it was the most experienced game developer in the studio, with a measurement page, a many-day soak test and a habit of reporting numbers before and after every change.
RISEN! and ZEKE! started on 16 September. Two days later the Owner asked them to "playtest themselves using chefs guidance". Both learned from CHEF!'s test pages and its log, and built the same kind of tools for their own games, with CHEF! writing them a short guide to its test pages.
It worked. RISEN!'s soak found that simply walking away from every camp won 192 of 300 runs, so the win condition was wrong; it fixed that. ZEKE!'s tools found six real problems, including a defender posted at a window being wounded the instant a zombie broke through. After the fixes, its thinking bots won about half their runs, and 4,000 simulated nights ran clean.
What was passed on wasn't code. It was a habit: measure, soak, then change one thing and measure again. Written down once, it could be picked up by a developer that didn't exist when it was written.
A new Tips setting in the Staff panel: keep tips for the restaurant (as before), give them to the server who served the table, or share them between the whole staff.
Staff now have morale (shown as a heart number). Tips they receive lift it, and it slowly settles back. Happier staff work a little faster.
Giving tips away costs you about $70 a day on a normal day, in exchange for happier staff.
No screenshot: the change is a small setting and a number beside each name.
The restaurant no longer looks blurry. The board used to be drawn at one fixed size and then stretched to fit your window, which softened everything, and more so when zoomed in.
It's now drawn at your screen's real resolution, so the art stays crisp at any window size, on high-resolution screens and when zoomed.
Two small seams in the counters that the sharper drawing showed up are fixed too.
No screenshot: the change depends on your screen, and a captured image can't show the before.
Cooks now look over what they put on the pass. A dish that came out poor, overcooked or has gone cold may get caught, binned and made again. Better cooks catch more of it.
A dish is only sent back once, so a struggling kitchen doesn't get stuck remaking the same plate.
You can hire a head chef ($300, about $20 a minute). They stand at the pass, fix poor dishes on the plate, and send back almost anything overcooked or cold. They're worth it for a big kitchen, too dear for a small one.
The day's results count the bad food caught.
The screenshot shows three head chefs to choose from.
CHEF! tried the counter in the game: no seams, and it reads as a solid block, but the stone top was almost as light as the kitchen floor.
The Art Director measured the stone against the concept art. It was a little too light and too cool, so it was warmed and darkened in code to match exactly, without touching its texture.
With the counter approved, the prompts are proven, and the first batch is released: 24 more CHEF! pieces (walls, floors, sidewalk, road, windows, doors, doorways and the welcome mat) are waiting to be generated.
Hiring now shows three people for each job, with their names, how good they are (stars for skill, speed, manner and care) and what they cost a minute. New people turn up every morning.
Some have a trait: Careless cooks burn food sooner, Perfectionists cook better but slower, Quick staff walk faster, Charming ones please guests, Tidy ones do chores faster, and Lazy ones are slow but cheap.
Better staff cost more. Your starting crew are ordinary, so the game plays the same until you hire.
The How to play screen now explains that clicking a bathroom sink lets you fit a paper towel dispenser or a hand dryer.
It also explains that toilet paper, soap and paper towels come from the pantry, that the busboy refills them, and what the bar under the toilet and sink means.
A restaurant whose front door is in the north, east or south wall now has a proper outside: sidewalk around the building and road beyond it, instead of indoor wood floor.
The road markings run along the street in front of the door, and the shop-front glass sits on the wall with the door in it.
The strip of wood that showed along the outside of the walls is paved over.
The screenshot shows a randomly generated restaurant with its door in the north wall, the same one that was painted as wood in Iteration 60.
When your cash drops below zero, the Money figure in the top bar turns terracotta with a minus sign, and the event log says so once. It says so again when you're back in the black.
Nothing pops up and the game keeps running: wages are still paid, you just can't buy or hire until you have the money.
No screenshot this time: the change is one number's colour.
The staff still have to tidy up before the day's results appear, and the next day still waits for you to click Next day.
If something couldn't be done, the results now say so at the top: dirty tables, dirty plates, a messy bathroom or the trash, all still there in the morning.
That happens when nobody on your staff can do the job (with no busboy, nobody takes the trash out) or when closing up runs out of time.
The screenshot shows a day played without a busboy: the results warn that the trash is still there.
Pick when the restaurant opens and closes with Hours in the top bar: open as early as 6:00 or as late as 14:00, close by midnight, at least four hours a day.
The clock starts an hour before opening, and the last guests are seated an hour and a half before closing.
Changing the hours during a day applies today if there's still time, otherwise from tomorrow.
Early openers get a quiet breakfast trickle and late closers a late-evening crowd; the usual 11:00 to 22:00 day plays exactly as before.
The screenshot shows the top bar with the new Hours picker beside Difficulty.
Click a bathroom sink to fit it with a paper towel dispenser ($30) or a hand dryer ($90).
The dispenser holds 20 towels. Each guest takes one, and the busboy refills it from the pantry like the toilet paper and soap. A guest who finds it empty is unhappier.
The hand dryer never runs out, but guests spend two extra seconds drying their hands under it.
The starting bathroom comes with a paper towel dispenser.
The screenshot shows the dispenser (left, with its towel and soap bars) and the hand dryer (right) with a guest drying their hands.
Staff now turn to face whatever they're using — the grill, the fridge, the sink, the dumpster, a table they're clearing — instead of always looking at the camera while they work.
They still face the way they're walking, and they keep looking at the last thing they used until they set off again, so nobody spins on the spot.
Guests sit on the toilet now, back to the tank, instead of standing in front of it. They're nudged forward a little so you can still see the toilet.
Nothing about play changed: the same 64 guests served over 10 games, seed for seed.
The GIF shows the cooking line: cooks with their backs to you while they work, faces toward you while they walk. Screenshot 141 shows the toilet.
CHEF!'s palette lived in the style guide as a table, and the game had copied the values into its own code by hand. Copies drift, so the palette now also ships as a small file the game can read directly, with the style guide still the one place the colors are decided.
Writing it down settled a real question. CHEF!'s warm terracotta sits right on the edge of being hard to read on the cream panels, so there are now two: the original for large type and accents, and a slightly deeper one for headings and small text. The game had already made that call in its interface; this makes it the rule rather than a local fix.
Each value carries its measured readability against the background it's used on, so nobody has to judge it by eye.
The game was tested on 60 randomly generated restaurants, with the front door on any wall, inner walls and doors, furniture in odd places, and some kitchens missing pieces or blocked on purpose. Several ways staff could get stuck were fixed.
Guests now arrive, queue and leave along whichever wall the front door is in, not always the west one.
A podium with its host spot or greeting spot blocked by furniture now uses another free tile beside it. Without a podium, the host and the guest meet just inside the door, on different tiles.
Idle staff no longer crowd onto one tile. Two servers waiting by the pass used to fill it and block anyone who had to walk through.
A dishwasher whose rack spot or sink is blocked uses a usable one, or sets the clean plates down where the cooks can still take them.
Staff never start the day on a blocked tile.
The default restaurant plays about the same: over 40 games, about 64 guests served.
The screenshot shows a randomly generated restaurant with its door in the north wall and guests lining up outside it.
A "?" button in the top bar opens a How to play panel. It covers the day (difficulty, opening the doors, rushes, closing, the next day), looking around (inspecting, zoom and pan, the mood faces), building (moving, R to turn, placing and stopping with Esc or right-click, deleting, counter items, and what makes a bathroom), and the pantry buttons.
Esc, "Got it" or a click outside the panel closes it, and index.html#help opens the game with it showing.
Hovering over the numbers in the Pantry and on the end-of-day results now explains what each one means.
The screenshot shows the How to play panel over the restaurant before opening.
The game was played for 30 days in a row on several restaurants and difficulties to look for anything that goes wrong over time. The normal restaurant ran all 30 days cleanly.
Fixed: in an overwhelmed restaurant, guests still waiting when the day ran out used to stay inside into the next morning. Now they go home and count as lost, with the reason "the restaurant closed".
Fixed: closing up used to wait for chores nobody on the staff could do. With no busboy, for example, the day waited on the trash. Those chores now wait for the next day.
Fixed: the game kept every order it had ever taken, about 50 more each day. Finished orders are now cleared out each night.
Staff of the same role no longer start the day stacked on one tile. Each new hire takes the nearest free spot next to their usual starting point, so all three cooks, both servers and the busboy can be seen from the first moment.
Nobody starts on a seat or in a doorway.
The pace of the game is unchanged: over 40 games, about 64 guests are served, as before.
The screenshot shows the starting crew by the pass and in the kitchen, each on their own tile.
On Medium and Hard, ingredients are now real stock. Every dish uses up its ingredients, and fresh food goes off: produce after a day, meat and bread after a day and a half, dairy after two and a half days. Spices keep.
The Pantry panel shows how much of each ingredient is on hand, how much is about to go off, and its par level (how much to keep), which you can raise or lower.
Each night the pantry is topped up to par for the next morning, and the order is paid at closing. You can add extra to tomorrow's delivery, or rush 5 in within the hour at double the price.
When a dish runs out, the menu marks it sold out. A guest who wanted it orders something else instead (a little disappointed), and leaves if nothing is left. A dish that burns with no ingredients left to remake it gets the same treatment.
Stock that goes off is thrown out at closing and shows up in the day's results, along with what was spent on ingredients. The menu shows what each dish costs to make: burger $5, chicken $4, salad $2.
On Easy, and in the endless test mode, everything is always in stock, as before.
With the starting crew and par levels, a day serves about 51 guests and a dish or two sells out near closing.
Bathroom supplies (toilet paper, soap, towels) will follow once a few design questions are answered.
The screenshot shows the Menu and Pantry panels at the start of day 1.
The game now plays in days. A clock in the top bar shows the day and time, starting at 10:00 with the doors shut. The sign on the door reads CLOSED, and "Open the doors" lets you start early.
The restaurant opens at 11:00. Guests come in waves: a lunch rush around noon, a quiet afternoon and a dinner rush in the evening. Easy has gentler rushes.
At 20:30 the last guests are seated. Once they've gone, the staff close up: tables cleared, dishes washed, bathrooms cleaned and all the trash taken out.
Then the day ends with a results screen: food sales, wages, spending, profit and cash, plus guests served and lost (with the reasons), average mood, rating, the busiest hour, and overcooked, burnt and cold dishes. "Next day" starts the next morning with the same restaurant, staff and money.
Staff are only paid while the restaurant is working, not before opening.
A full day takes about 14 minutes at normal speed. With the starting crew about 51 guests are served, and nobody walks out.
The starting restaurant currently loses money every day (wages outrun sales). How to balance that is a question for the Owner.
The sign on the door now fits its words: OPEN and CLOSED shrink to fit the sign's plate.
The first screenshot shows the results at the end of day 1. The second is a close-up of the door sign, closed and then open.
Waiting now wears guests' mood down more slowly, so a well-run restaurant earns about 3 stars instead of about 2.
Over 40 games of 15 minutes each with the starting crew, the average rating is 3.0 stars and the average guest leaves at mood 59. About 64 guests are served, and almost nobody walks out.
Kitchens that are short a station or a cook still lose guests; a one-prep kitchen loses about 6%.
This is the starting point for a planned system in which guests expect more as a restaurant's rating rises.
Food on the grill now stays there until the cook can take it to the next station. If every prep station is taken, it keeps cooking: after 6 seconds it smokes and is overcooked, and after 15 seconds it burns.
A burnt dish goes in the trash, and the next free cook makes it again. An overcooked dish still goes out, but it's worth less, and the guest notices.
Patties and chicken are now flipped halfway through grilling.
A new resting rack ($25) sits on a counter. A cook can move finished food onto it, freeing the grill while they wait. On Hard a rack won't hold beef and chicken together; on easier difficulties it will.
Dishes cool while they wait at the pass, and steam fades as they do. A dish left long enough loses up to 40% of its quality, and the guest's mood follows.
Easy never burns anything. Medium gives the cooks twice as long before food overcooks, burns or goes cold.
The Performance panel counts overcooked, burnt and cold dishes.
In the default restaurant nothing burns, but about two thirds of dishes cool a little at the pass. In a kitchen with only one prep station, a resting rack raises guests served from 54 to 61 per game.
The clip is staged: every prep station is taken, so the circled cook's burger smokes, then burns, and the cook starts it again. The screenshot shows a burger waiting on a resting rack while the grill is free.
Every guest now has a mood, shown as a small face beside their head: green when happy, yellow when so-so, red when unhappy.
Waiting wears mood down: in line, for someone to take the order, and for the food. A guest whose mood runs out walks out. This replaces the old fixed waiting limits.
Good moments lift it: a quick greeting, getting a table, ordering, good food and a friendly server.
A messy bathroom upsets the guests who go in, and dirt tracked outside upsets guests who walk past it.
Cooks with truly nothing to do now stop by a table to say hello, which cheers the guests up. One cook always stays in the kitchen, and a visiting cook heads back as soon as a ticket comes in.
A guest's final mood is their satisfaction, and the last 30 guests make the restaurant's new star rating in the Performance panel. Guests who walked out count as zero. Later the rating will bring in more or fewer guests.
The pace barely changed: over 40 games of 15 minutes each, about 63 guests served and 4% lost, against 64 and 5% before.
The clip shows an idle cook (circled) walking over to check on a table. The screenshot shows happy, so-so and unhappy guests at neighbouring tables.
Bathrooms are now rooms you build. Any area closed off by walls, with a door, a toilet, a sink and a trash can, becomes a bathroom, and you can build as many as you like.
Doors, toilets, sinks and trash cans can now be bought in the editor.
In edit mode each bathroom is tinted green when it works, or red with a list of what's missing, such as "needs a sink" or "needs a door".
Guests pick the bathroom with the shortest line, and each bathroom keeps its own line, mess and trash can.
If you break a bathroom while someone is using it, guests head back to their tables and the busboy drops the job. The chore comes back once the room works again.
A messy bathroom now leaves a dirty patch on the floor outside its door, which fades after half a minute.
The default restaurant plays exactly as before: over 40 games of 15 minutes each, about 64 guests served and 5% lost.
The clip shows a bathroom being built in the kitchen: walls, a door, then the toilet, sink and trash can. The red list shrinks until the room turns green.
On Easy, the bathroom never gets messy and its trash can never fills. Guests still use it and still line up for it, but nobody ever has to be sent to clean it or empty its bin, so a new player can focus on seating and cooking.
This follows the Owner's rule for difficulty: Easy switches off the upkeep chores while keeping the flow of the game.
Medium and Hard are unchanged: after 10 visits the bathroom needs cleaning, and its trash can fills from visits until the busboy empties it.
Posts with an animated clip used to show it as a tiny thumbnail under the still. Now the clip is the main picture and the still becomes a small thumbnail beside it — the trash run (CHEF! Iteration 43) shows only its clip, since the clip already covers the whole trip.
Before/After posts keep the pair on top, because a clip only shows the "after"; the clip now plays underneath at a readable size (progress/059-shipped-pair-with-gif-below.png, the busboy cleaning the bathroom).
A clip is never shrunk to a thumbnail anywhere, and a tiny sprite clip still shows at its real in-game size.
A guest's bathroom visit now has two steps: they use the toilet, then turn around and wash their hands at the sink. Before, they stood still in the middle of the room for the whole visit.
The visit takes as long as before (6 seconds), so the game's pace is unchanged.
The clip follows the circled guest in, to the toilet, to the sink, and back out.
Fixed a kitchen jam. A cook who leaves food on a prep station to fetch a plate keeps that station. Other cooks used to queue in front of it even when the second prep station was free, and could block the first cook from getting back for minutes.
Cooks now pick a free station when there is one, and switch to one that frees up while they wait.
Over 40 games of 15 minutes each, the kitchen got much faster: about 64 guests served and 5% lost, up from 61 and 9%. No game lost more than 15% of its guests, where the worst used to lose 31%.
The screenshot shows both prep stations in use: one cook preps a salad on the left while the circled cook brings a plate back to their own salad on the right.
People who step aside to let someone past now walk to the side instead of jumping a whole tile in one frame.
The small sideways shifts people make when two of them pass on one tile, or when the hostess makes room at a table, now slide into place too.
Over 5 test games, the old build had 147 moments where someone jumped further than a walking step. The new build has none.
Stepping aside now takes a moment of walking, which costs a little speed: over 40 games of 15 minutes, about 61.4 guests served and 9.1% lost, against 62.1 and 8.3% before.
The first clip (119, the previous build) shows the circled guest at the door jumping sideways to let a leaving guest out. The second (120) is the same moment now: the guest walks aside.
Fixed a stand-off at the front door. A guest leaving could get stuck in the doorway because the only tile outside was full: one spot taken by the next guest in line, the other by a guest waiting to come in. The waiting guest in turn waited for the leaving one, so both stood there until a safety timer let them push past.
Now a guest waiting at a door steps aside when the person in the doorway needs their tile to get out.
Over 40 games of 15 minutes each, moments with people going both ways in the front door dropped from about 190 to none, and the 12-second safety timer never had to fire. The game also got a little faster: about 62 guests served and 8% lost, up from 61 and 9%.
The clip shows the guest with the blue ring stepping aside so a leaving guest can get out, then walking in. The step aside is still a jump rather than a walk; smooth movement within a tile is next.
Taking the trash out to the dumpster is now the busboy's job alone. Cooks and servers no longer do it.
Over 40 games of 15 minutes each, the busboy made all 40 trash runs, where cooks and servers used to split them. Nothing slowed down: about 61 guests served and 9% lost, no games that stopped serving, and a full dumpster waits at most about a minute for its run, as before.
The screenshot (104) zooms in on the busboy, circled, emptying the full dumpster.
The animated clip (107, v0.0.50) follows the busboy's whole trip: out the front door, emptying the full dumpster, and back in.
Cleaning the bathroom and emptying its trash are the busboy's jobs now. A server only takes one when the busboy is busy.
If the busboy frees up while the server is still on the way, the server hands the job back and returns to the floor.
Over 40 games of 15 minutes each, busboys now spend about 348 seconds on bathroom chores and servers about 19, where it used to be 299 and 74. Throughput didn't change: about 61 guests served and 9% lost.
In the before shot (100), a server cleans the bathroom while the busboy stands idle. In the after shot (101), the busboy cleans while a server is free for the dining room.
The animated clip (112, recorded on v0.0.50) follows the busboy: he takes his turn at the bathroom door, cleans (the puddle goes), and leaves.
People now take turns at one-tile doorways, like the front door. Nobody steps into a doorway while someone is coming through it the other way; they wait on their own side.
If two people reach the door together, whoever is already in it goes first, then guests on their way out, since they free up tables. After four seconds of waiting, turns alternate, so a long stream of people leaving can't hold arrivals back forever.
Someone waiting outside a door also leaves room in front of it, so the people coming out have somewhere to step.
The line of guests waiting to be greeted no longer stands inside the doorway. It now starts just outside, on the sidewalk.
Two safety nets stay in place: after twelve seconds a wait gives up and normal crowding rules apply, and the four-second squeeze-past from Iteration 36 is still the last resort.
Over 40 games of 15 minutes each, the moments with people going both ways in the front door dropped from about 4,700 ticks to about 190. Waiting costs a little: about 61 guests served and 9% lost, where the same games served 62 and lost 7%.
The before shot (098) shows a leaving guest, a party walking in and guests in line piling into the door together. In the after shot (099), the leaving guest has the door to themselves while the arriving guest waits outside. The animated clip (105) was recorded later, on v0.0.50, which adds Iteration 44's step-aside fix.
Cooks no longer leave the kitchen to clean the bathroom. The busboy and servers do that.
A cook with nothing to cook now helps with the dishes. The dishwasher has first call: a cook only takes a washing round while no dishwasher is free, and hands it back if one frees up before the cook has picked up any plates.
With no dishwasher on staff, the cooks keep the plates washed between tickets. Cooking always comes first.
Later, when guests' mood matters, a cook with really nothing to do will also be able to visit tables for a mood boost. Nothing is built for that yet.
Over 10 games of 15 minutes each, a default game now serves about 62 guests and loses about 8%. Before it served 61 and lost 9%. Cooks spend about 11 seconds per game helping with dishes.
In the before shot (094), a cook heads through the dining room to clean the bathroom. In the after shot (095), a cook washes dishes while the dishwasher carries a rack.
The animated clip (111, recorded on v0.0.50) follows a ringed cook who, while the dishwasher is busy with an empty rack, fetches dirty dishes and washes them.
Counters now run straight through the appliances built into them. The fridge and grill sit in one continuous counter along the north wall, and the prep island reads as one piece. The pass and dirty-dish bin sit in an unbroken service counter, and the sink and dish rack in the back counter. Before, each counter broke into separate pieces around every appliance.
A dishwasher (and later any other built-in appliance) can now be placed straight onto a counter tile. It takes that piece's place in the run, and you get the counter's resale value ($20) back.
If the way it's turned would put its front against a wall or another counter, it turns to face into the room by itself.
Counters with something on them can't be replaced, and walls and counters can't go onto counters.
The placement highlight now shows green over a counter tile when the item can take its place.
A free-standing appliance, with no counter next to it, looks the same as before.
Nothing about how the kitchen works changed, so a normal game plays exactly as before: about 61 guests served and 9% lost.
The dishwasher machine is now its own one-tile station. Buy it with "+ Dishwasher ($60)" in the furniture card, place it and turn it like any other station. It used to be a small item you put on a counter.
When one is placed and its front is clear, the dishwasher (the worker) loads each batch into the machine instead of washing by hand at the sink. The machine washes twice as fast. Its window fills with suds and a green light comes on while it runs, and the worker shows "RUNNING THE DISHWASHER".
If the machine's front is blocked, the dishwasher goes back to the sink.
The rest of the dish round is unchanged: dirty plates from the bin, washed, then into the rack by the sink.
The default restaurant doesn't include a machine, so a normal game plays exactly as before: about 61 guests served and 9% lost. With one placed in the kitchen, the same test games serve about 62 and lose about 6%.
In the before shot (090), the old counter-top dishwasher sits unused while the sink does the washing. In the after shot (091), a placed machine runs a load.
The animated clip (113, recorded on v0.0.50 with a machine built into the back counter) follows one round: four dirty plates fetched, the machine running with suds in its window, and the plates racked.
Fixed: two servers could go to the same table to take orders and end up standing on the same tile. Each guest used to call for a server separately, so a party of two could get two servers at once.
Now a table orders all at once, with one server.
Once everyone at the table has read the menu, one server comes over and shows "TAKING ORDERS".
The guests order one at a time. Each shows a speech bubble with the dish they want.
When everyone has ordered, the server takes the whole table's tickets to the kitchen together.
Servers also pick a corner of the table that nobody else is standing on or heading to.
On Easy, each guest takes 1 second to order instead of 2.
Also fixed: a rare traffic jam in the front door. Guests leaving and a party coming in could block each other for good, and one test game stopped serving after six minutes. Someone stuck that way for four seconds now squeezes past.
Over 10 games of 15 minutes each, a default game now serves about 61 guests and loses about 9%. Before it served 59 and lost 10%.
In the before shot (088), two servers stand on one tile at a table, their status labels overlapping. In the after shot (089), one server is taking orders and the first guest's bubble shows a burger.
The animated clip (106, recorded on v0.0.50) follows one server taking a table of three's orders, one bubble at a time.
Workers now use a station only from the tile in front of it: the fridge, grill, prep station, dish sink, dish-rack spot, bathroom sink, toilet, trash can and dumpster. The podium works the other way round: the host stands behind it and guests come to its front. The pass, dirty-dish bin, plating table and counters can still be used from either side.
Turning a station changes where people stand to use it.
If something blocks a station's front, nobody can use that station. In edit mode its arrow turns red.
If there's another usable station of the same kind (the second prep station, say), cooks use that instead.
If there isn't, the cook waits with "WAITING: GRILL IS BLOCKED" rather than skipping the step, and carries on once the front is cleared.
A worker who can't reach where they're going now says "CAN'T GET THERE" and tries again every two seconds. Before, a worker who couldn't reach a station's tile would use it from wherever they ended up. In the before shot (086), a cook is grilling from the tile beside a blocked grill.
Guests skip their bathroom trip if the bathroom sink's front is blocked.
The default restaurant already had everything facing the right way, so a normal game plays exactly as before: 59 guests served and 10% lost, over 10 games of 15 minutes each.
The animated clip (108, v0.0.50) is staged: a counter is put in front of the grill, the cook waits, and once it's removed the cook grills from the front. In edit mode the arrow turns from red to white.
Every station now faces one of four ways. In Edit Layout, press R over a station to turn it a quarter clockwise. While placing something you've just bought, R turns it before you click.
A small arrow on the tile under the cursor shows which way the station faces.
The default restaurant's stations face sensible ways. The fridge and grill have their backs to the north wall, and the sink its back to the south wall. The prep stations face the cooks, and the waiting chairs face into the room. The podium now uses its front-on art, with the host standing behind it.
A guest in a waiting chair sits facing whichever way the chair is turned.
A facing is part of the station, so it stays when the station is dragged, and any future layout save will keep it. The game has no save feature yet.
The toilet still picks its own facing from the walls around it, and tables are square, so neither turns.
For now, turning a station changes only how it looks. Using stations from their front comes next.
The animated clip (110, recorded on v0.0.50) shows R pressed four times over a waiting chair: it turns through all four facings, and the arrow follows its front.
Fixed: items bought for a counter (register, spice rack, napkin dispenser, potted plant, dish rack, dishwasher) were never drawn. The purchase went through and the dishwasher still sped up washing, but the counter looked empty. They now sit on the countertop.
The before and after shots show the same six items on the service counter: invisible before, drawn after.
Cooking line: the fridge and grill are built into a counter along the north wall.
Island: an island in the middle, level with the pass, holds the plating table and two prep stations side by side.
Dish area: the dirty-dish bin, the sink and the dish-rack spot sit together in the corner by the kitchen door.
One tile each: every piece takes one tile.
There are now two prep stations. Recipes use the prep counter more than anything else, and three cooks used to queue for one.
Fixed: cooks used to walk out through the kitchen door and round to the dining-room side of the pass to set a dish down. They now use the pass from the kitchen side.
Over 10 games of 15 minutes each, a default game now serves about 59 guests and loses about 10%. Before this change it served 54 and lost 14%. Cooks walk about 1,080 seconds per game, down from about 2,030.
The kitchen is quicker than it was before plates had to be carried at all (Iteration 29: 57 served, 8% lost), so the automated throughput check is back at its original limit of 25% lost.
In the before shot (080), the prep counter and grill stand in open floor and a cook heads out of the kitchen door. The after shot (081) shows the new layout.
Clean plates now live in portable dish racks of 10. The dishwasher fills a rack at the sink, and once it's full someone carries the whole rack to a new plating table in the middle of the kitchen, near the cooks. Cooks take their plates there instead of walking to the sink.
Who carries a rack follows the Owner's order: the busboy if he's free, otherwise the dishwasher, otherwise a cook. When a rack at the plating table is empty, someone carries it back to the sink for refilling.
While there's no rack at the sink, the dishwasher waits with his clean plates ("WAITING FOR AN EMPTY DISH RACK"). If the cooks run out of plates, a partly filled rack is carried over early. On Easy, racks still move, but the plating table never runs dry.
It wins back most of what Iteration 30 cost. Over 10 games of 15 minutes each, a default game now serves about 54 guests and loses about 14% of them. Before this change it served 42 and lost 36%. Cooks now spend about 212 seconds per game fetching plates, down from 558.
The racks show their plates, and a rack being carried is drawn in the carrier's hands.
In the screenshots, 079 (before) shows a cook walking the length of the kitchen for a plate. 078 (after) shows the busboy carrying a rack while a cook brings a plate back from the plating table.
The animated clip (117) was recorded on the v0.0.37 build itself: the busboy (ringed) returns an empty rack to the sink, carries a full one to the plating table, and cooks walk over to take plates.
The dishwasher now does real rounds. He walks to the dirty-dish bin, takes up to 4 plates from the kitchen side, carries them to the sink and washes them, then stacks them on a new clean dish rack on the back counter beside the sink. Plates used to jump straight from the bin to the sink and back into stock.
Cooks now fetch their plates. When a dish is ready, the cook leaves the food at the station, walks to the clean rack for a plate, brings it back and plates the dish, then takes it to the pass. If the rack is empty, the cook waits there with "WAITING FOR A CLEAN PLATE".
The sink now shows what's happening: dirty plates stacked in the basin, running water and suds while a load is being washed. Before, the sink always looked dry and empty, even mid-wash. The clean rack shows one standing plate per clean plate on it.
"Free plates" now means the plates on the rack, and "Dirty dishes" counts every dirty plate, whether on the bin, in the dishwasher's hands or in the sink.
The extra walking costs the kitchen. Over 10 games of 15 minutes each, a default game now serves about 42 guests instead of 57, and loses about 36% of its guests instead of 8%. Plates never ran short; the time goes on cooks walking to the rack. The balance is provisional.
Before and after, zoomed in on the kitchen: 076 shows the dishwasher "washing" at a dry, empty sink. 077 shows a load in the sink, the rack on the back counter and a cook bringing a plate back to the prep counter.
The animated clip (118) was recorded on the v0.0.36 build itself: the ringed dishwasher's whole round (bin, sink, rack), with a cook walking across the kitchen to the rack for a plate, the walk Iteration 31 then cut.
After buying a counter or wall, the item stays in your hand: every click on an empty tile buys and places another one, until you press Esc or right-click. It also stops if you run out of money.
Right-clicking the board no longer opens the browser's menu.
The hints under the board and in the shop say so.
The animated clip (114, recorded on v0.0.50) shows one Wall purchase placed four times by clicking, then a right-click to stop. The hint text has changed since (it now also mentions R and replacing counters), but the placing works the same.
Only one person can be in the bathroom at a time, guests and staff alike. Everyone else waits in a line that starts just outside the door (I2 in the default layout) and runs along the wall. The line is worked out from wherever the door is, so it follows the bathroom if the layout changes.
Guests show "WAITING FOR RESTROOM" while in line. Staff show "WAITING TO CLEAN BATHROOM" or "WAITING TO EMPTY BATHROOM TRASH", then "CLEANING BATHROOM" or "EMPTYING BATHROOM TRASH" while they work, then "LEAVING BATHROOM" as they step out.
The bathroom now needs cleaning after 10 uses, instead of getting messy at random while the restaurant is open.
Fixed: the busboy could get stuck in the bathroom. After cleaning it he had nowhere to go, so he stood inside it. He now waits by the dirty-dish bin when idle.
In the screenshot, the busboy is cleaning the bathroom and a guest is walking to the front of the line.
The animated clip (109, recorded on v0.0.50) shows a guest, ringed, waiting at the bathroom door until the guest inside comes out, then going in.
CHEF! now has its own delivery of its logo set: the hat mark and icon, the wide header logo, the stacked logo, the wordmark, one-color icons, favicons from 16 to 512 pixels, and a share image.
The game uses them in its new warm-wood interface: the header logo and the browser-tab icon.
The real CHEF! logo, from the Art Director's brand kit, replaces the magnifier and plain "CHEF!" text in the header, and the browser tab now shows the chef-hat favicon.
The interface now looks like the concept art: a dark walnut backdrop with a warm lantern glow, a thick wooden frame around the restaurant, cream panels with terracotta Georgia headings, and chunky, rounded terracotta buttons. The event log is a slate chalkboard in a wooden frame, like the "Good Food" signs in the art.
Everything follows the Art Director's CHEF! style guide: terracotta #B54E1F on light surfaces only, cream and dark-brown text, and no cold greys or plant green in the chrome.
Long staff statuses such as "TAKING DISHES TO COUNTER" now stay on one line, so the whole eight-person crew fits in the staff list.
Before and after, at desktop (1440px) and phone (390px) widths: 071/072 and 073/074.
CHEF!'s logo now comes as the same set every studio project has: a mark, an icon, a wide header logo, a stacked logo and a wordmark on standard canvases, plus favicons and a social card.
The art is unchanged — the hat still reads clearly at favicon size.
The logo slide in CHEF!'s brand deck was redesigned to show the set, including the icon at 64, 32 and 16 pixels.
Both images are reconstructed: composed afterwards from the committed files.
The game now has a difficulty setting: Easy, Medium or Hard. Easy skips most mechanics and Hard will have the most (perishable produce, individual spices and herbs, and more), so during development the game runs on Hard, where every mechanic is switched on. There's no in-game picker yet.
On Easy the plate supply never runs out. A dish still needs a plate, and that plate still goes dirty and needs washing, but when none is free a new one is added, so cooks never wait. On Medium and Hard the kitchen has exactly 30 plates, as in Iteration 25.
Measured over 10 games of 15 minutes each, with no dishwasher: Easy served 57 guests (the same as with a dishwasher) and ended up with about 61 plates and 56 of them dirty. Hard served exactly 30 and lost half its guests.
The Pantry card now shows the actual difficulty instead of always saying "Easy mode". Its note says ingredients are always in stock at every difficulty for now, which is still true.
Plates are now a real resource. The restaurant owns 30, and each is always in one place: free, in use (a dish is on it), dirty, or washed and waiting to be put back.
A finished dish can't go to the pass without a free plate. The cook stays at the last station, still holding it, labelled "WAITING FOR A CLEAN PLATE", until one frees up. That also blocks any other cook who needs that station. Running out of plates never stops guests being seated; they just wait longer for their food, and their patience does the rest. Later, that wait can have its own consequences, like food burning on the grill.
Only plates that actually reached a table come back dirty when it's cleared, and a plated dish whose guest left goes straight into the dirty stack.
The Performance panel now shows free plates, plates in use, and total cook time spent waiting on plates, so you can see the plate cycle breaking down as it happens.
The dishwasher now matters. Over 10 games of 15 minutes, a default crew with a dishwasher never dropped below 17 free plates and lost 8% of its guests. Without one, the kitchen ran out of plates 7–8 minutes in every time, served exactly 30 guests (one per plate), and lost 52%.
A new game now opens with three cooks instead of two. Two cooks could finish about 2.8 orders a minute while about 5.6 guests arrived, so a default game lost roughly 39% of its guests.
Six options were measured over 10 games of 15 minutes each. One extra cook was the clear winner: losses fell from 39% to 12%, guests served rose from 39 to 56 on average, and the restaurant ended with more money ($328 vs $261) despite the extra wage. A fourth cook only trimmed losses to 7% and made less money; halving arrivals cut losses but served fewer people.
This is a provisional test balance, not a final design, and is marked as such in the project rules. A new automated test fails if a default game starts losing a quarter or more of its guests.
On a 1440px-wide screen the Staff panel's five hire buttons didn't fit on one line, so "+ Dishwasher" was cut off the edge of the card. The buttons now wrap onto extra rows.
The staff list was capped at about five rows, so with the new seven-person opening crew the last member was hidden until you scrolled. The list now shows the whole default crew and only scrolls once you've hired more.
Checked at 1440, 1024 and 375 pixels wide: no hire button is clipped in either card, the page never scrolls sideways, and the full crew is visible at every width.
A new game now starts with a dishwasher (the blue apron at the kitchen sink) alongside the hostess, two servers, the busboy and two cooks.
Before this, only a dishwasher was allowed to wash dishes, but the opening crew didn't include one, so a default game never washed a single plate and its clean-plate stock drained to zero within ten minutes. Across ten test games, the lowest the stock now gets is 22 of 30.
Worth knowing: running out of plates doesn't yet stop anyone being seated, so the dishwasher doesn't change how many guests get served; it keeps the dish pit sane and costs its $6/min wage (about $60 less money after ten minutes).
A default game used to stop serving almost entirely around the six-minute mark, and adding staff didn't help. Two things were wrong, and both are fixed.
Abandoned orders stayed live. A guest who gave up waiting still had their order on the board, so a cook still cooked it and a server still carried it out to an empty chair. Now leaving cancels the guest's order and any not-yet-started work for it. A cook mid-recipe stops at the next step, and a server already carrying the plate drops it rather than delivering it to nobody. Food that was finished but never collected is binned at the pass.
The kitchen only ever cooked for people about to leave. Once more guests were arriving than two cooks could feed, cooks always picked up the oldest ticket, which by then was already near its guest's patience limit, so it was cancelled partway through. Both cooks stayed busy while finished orders dropped from about 2.8 a minute to about 0.2. Cooks now skip a ticket whose guest will have left before it could reach them. How long an order takes is learned from real orders as the game runs, not guessed.
Result, same default game and crew: served by minute 15 went from 14 to 38, and guests lost from 51 to 22. Across ten different random seeds the game now serves 10–14 more guests between minutes 6 and 10, where it used to serve 0–1.
Four new automated tests cover this, including one that fails if a default game stops serving after minute 6. An older test comparing a good and a bad kitchen layout was only ever passing 1 served vs 0; it now compares ten-minute runs across three seeds, where the good layout clearly wins (53 vs 21).
Four fixes, found by reviewing why certain problems kept recurring rather than by chasing them individually:
ES modules were being served cached. The game is unbundled modules at stable URLs with no cache busting, so a reload could silently re-run the cached copy of a file just edited. It never presents as a caching problem — it presents as "the fix didn't work," which invites re-fixing or reverting changes that were already correct. Caught directly: a verified edit was on disk while the page demonstrably ran the old function body. tools/dev_server.py now serves everything Cache-Control: no-store; use it instead of python -m http.server.
An unreachable destination froze customers permanently and leaked their table.isPathComplete() required path !== null, so a failed pathfind reported "not complete" forever. Worker tasks survived by accident via a separate guard in BaseTask; the customer state machine had none. A guest sent to a walled-off bathroom never finished eating, so their table was never released or marked dirty — one sealed door quietly removed a table from the restaurant for the rest of the run. Reproduces on the pre-existing LEAVING and WALKING_TO_TABLE states too. Null now counts as complete, the restroom trip refuses to start when the bathroom is unreachable, and a related occupancy-claim leak on the same path was closed. Two regression tests added.
Wall and counter runs looked like rows of separate blocks. Two compounding causes. The fill callback ran once per piece and stretched a fixed texture crop into each piece's rect — but a straight run's arms are ~5x narrower than its hub, so the material was squashed to a fifth of its width on the arms and changed scale twice per cell. And the trim windows were not tileable: measured by tiling each crop and averaging the luminance step across the cell boundary, the counter stepped 35.4 horizontally / 40.4 vertically and the wall 10.9 / 64.6, i.e. a hard seam redrawn at every cell. Pieces are now clipped as one region with the fill mapped once across the whole tile, and both trim windows were re-solved against that measurement: counter now 0.9 / 1.2, wall 3.1 / 2.0.
The sprite sheet is not a real 4-direction set. Two independent traps, both of which read as "the code is drawing it wrong." First, a _n/_s/_e/_w suffix names the side the object's BACK is on, not the side it faces. Second, and worse, four files does not mean four views: measured by mean per-pixel difference, 8 of 15 sprite families ship the same artwork twice on the n/s axis (toilet 15.0 vs 86.5 for the genuine e/w pair; counter 6.6, bathroom_sink 7.2, trash 12.0, pass 13.7, grill2 16.5, fridge2 20.0, table 5.1), and table/small_table/chair2 are duplicated on both axes, making them effectively single-view assets. chair3 is distinct on both axes, which is very probably the real reason the chair art had to be swapped twice before it looked right — that was never a code bug. Where a real crop exists it is now used; where the needed view genuinely doesn't exist in the art, it is synthesized by flipping.
Seated guests who have been served now sometimes need the restroom. The roll happens once per meal (35%) the moment their food arrives; if it fires, they get up mid-meal, walk to the bathroom, spend a few seconds there, and return to the exact chair they left, with their meal timer frozen for the whole round trip so the detour doesn't eat into how long they've been sitting. Arriving in the bathroom is what applies the consequences: an independent chance each of leaving the room properly messy (posting a CLEAN_BATHROOM job) and of adding to the bathroom's own trash can. The can is a new per-station fill level, separate from the restaurant-wide dumpster total, and once full it posts a new EMPTY_BATHROOM_TRASH job. Busboys are first in line for that job and can now also take CLEAN_BATHROOM, which was previously server/cook only.
The fixtures were rearranged to suit: the door moved from the south wall to the east wall, the toilet and trash can swapped into the room's lower row, and the old south doorway was walled back up. The toilet's facing is no longer a hardcoded value but is derived live from which side of it is actually open, so its bowl always opens into the room and its tank always sits against a wall — and it stays correct if the fixture is ever dragged elsewhere in Edit Layout.
Not screenshotted, deliberately: the EMPTY_BATHROOM_TRASH job itself. It is implemented and verified end-to-end by automated test (can drains back to zero, job completes), but the trash can fills slowly enough at default traffic that a live capture wasn't reachable — made worse by the pre-existing throughput stall described in Iteration 20, which means very few guests ever reach the EATING state that a restroom trip requires in the first place. Recording the gap rather than staging a scene that normal play doesn't produce.
Two illustrations for CHEF!'s brand deck: the whole restaurant floor in the middle of service, and a closer view of the dining room with the kitchen behind it — warm lantern light, wooden furniture, cheerful staff.
An 8-slide brand and art reference deck for CHEF!: overview, visual identity, sprite and concept reference, a current screenshot, logo treatment and key art.
Warm cream and terracotta, like the game itself: cozy and orderly, never gritty.
It shows CHEF!'s full furniture and fixture sheet — every table, chair, counter and kitchen appliance, from all four sides — to show the range of the game's art in one picture.
A static devlog (devlog/) with one universal feed and one feed per game, both views over the same data/posts.json — a post is never duplicated, only filtered.
Posts are generated, not written: a read-only sync (scripts/sync_devlog.py) parses each registered game's own PROGRESS.md, one milestone entry per post, copies the screenshots that entry references, and keeps the milestone's original date (inline Date: line, else a hand-derived overlay, else first-seen — never the sync date).
Full backfill of CHEF! and GENERAL!'s shipped history, then an hourly sync that reports thin new posts to the Owner and Project Manager.
Studio and per-game branding (logos, badges, per-game accent theming), a filter-chip switcher on the universal feed, a stats strip, a screenshot lightbox, and a visible site version tag.
Three separate, unrelated fixes to how pawns move and stand near furniture. First: workers and guests could path directly through a chair (table seat or podium waiting chair), occupied or not — fixed by including every waiting chair (not just table seats) in the shared chair-avoidance set used everywhere a walk gets planned, including the congestion "yield" maneuver that previously ignored it. Second: every agent in the game briefly flickered to face backward for exactly one frame at every waypoint arrival, confirmed via direct simulation stepping to happen on every single arrival, not an occasional glitch — root cause was computing facing from an agent's own continuous position at the exact instant it briefly equals its just-reached waypoint; fixed by computing facing from grid-cell-to-grid-cell direction instead, which has no equivalent zero-delta instant (flicker count went from thousands per run to zero). Third: Restaurant.serverStandingPointFor now takes a side preference — the hostess prefers the side of a table closest to the podium, a server/busboy the side closest to the kitchen pass — so the two naturally spread to opposite corners of a table instead of converging on the same one.
Added a real walkable kitchen door (with actual swinging-door art, distinct from the food-handoff pass tile) after discovering busboys assigned to wash dishes had no physical path into the kitchen at all — the counter wall separating kitchen from dining had exactly one gap (the pass), which is an interaction point, not a walkable passage. Added a dedicated dishwasher role (hireable, spawns at the sink) to own washing and resetting dishes end to end; busboy and cook no longer touch that job, keeping busboy purely front-of-house.
Fixed the hostess and an escorted party's first member visibly "racing" each other to the table, each halving the other's speed by repeatedly re-entering the same shared cell — she now gets a real head start (tuned to 1 tile of distance, not a fixed time, after an earlier time-based version read as too long a pause) before the party is released to follow, and while she's leading a party out she never lets a guest draw level with or pass her (with a capped, repeating pause if that would ever stall the walk entirely — found and fixed a real stand-off this could otherwise cause, confirmed via direct simulation). The busboy got its own red outfit color so it reads apart from the server's black at a glance. A front-facing hair-rendering bug (hair geometry crossing through the eyes on a long-haired pawn facing the viewer) was found and fixed, verified via an isolated rendering harness.
The animated clip (116) was recorded much later, on v0.0.50: the hostess (ringed) leads a party of three from the podium to their table ahead of them, and waits there while they sit.
The whole "guest walks up to be greeted" pipeline was rebuilt after repeated reports that guests weren't stopping at the right tile and later party members were skipping ahead of their own leader. Fixed points now: one exact podium speaking cell (where the party leader stops and chats), a single continuous outside queue line (not two separate columns) that every other waiting party lines up behind, and party-leader identity decided by spawn geometry (whoever's placed closest to the aisle at spawn is the leader with a natural head start) rather than by re-sorting the party after the fact — an earlier attempt at fixing "who's the leader" by re-ranking on distance or reversing queue order was replaced with this simpler, more direct fix per direct user correction. Queued guests now face whoever is directly ahead of them in line (direction varies by which leg of the line they're on). Customers exit and spawn on fixed, opposite edges (north exit, south spawn) instead of a random choice between the two. Seating a party is now hostess-only work, not something a passing server can also claim. Several genuine deadlocks were found and fixed via direct simulation stepping along the way (not just code review) — a podium/greeter-point collision that let the hostess permanently block the one doorway, a queue-slot promotion rule that could let two customers deadlock waiting on each other's cell, and a lead-attribution bug that could misattribute a second party's greeting visuals onto the wrong guest under load.
The animated clip (115) was recorded much later, on v0.0.50: the hostess reaches the podium and the lead guest of a party of three shows 3 in a speech bubble. The line behind them now starts outside the door (Iteration 41) instead of in the doorway.
A toggleable debug overlay (the "🐞 Debug" button) draws a faint checkerboard tint plus a bold, readable coordinate label over every grid cell — legible on a vertical side-monitor at a glance, after direct user feedback that an early pass was too small/yellow to read there. Coordinate format converted from raw numeric pairs to spreadsheet-style column-letter + row-number (A1, B6, ...) per the workspace-wide ../AGENTS.md convention for grid/tile-based UIs.
The row of 6 waiting chairs by the podium (all facing east) and pawns gained real side/profile facing art (a visible single hand on the near arm) instead of only front/back. Movement direction now drives which way a walking pawn faces. A "podium gate" was added so a customer only becomes eligible to sit in a waiting chair after actually meeting the host at the podium, not before — closing off a way to skip the greeting. Newly spawned customers no longer overlap each other or the dumpster on arrival.
(progress/056-shipped-wide-baseline-full-layout.png — a full-canvas checkpoint taken the next day specifically because the folder was almost entirely narrow/cropped shots relative to actual iteration count, not tied to a specific feature — is the baseline this file's own Iteration 14 onward, below, picks up from. It's also what prompted the "periodic wide-shot checkpoint" rule now in ../AGENTS.md.)
The dining room grew from 4 tables to the 3-column/12-table layout the game still uses today (3 vertical columns, each a paired 4-top north and south plus a standalone 2-top in between — see createDefaultRestaurant in Restaurant.js). The outside queue became a real single-file line rather than a loose cluster. Chair art went through two successive sprite swaps (chair2, then chair3) chasing a cleaner look, plus an empty-chair cutout fix and a chair-hole resize.
A long chain of small, iterative fixes to chair and seat rendering: draw-order/occlusion fixes so a chair doesn't wrongly cover or get covered by the wrong neighbor, a south-seat position nudge (sitting position drifted slightly off-center relative to its table), chair sprite transparency fixed (an artifact showing through where it shouldn't), a chair/table alignment gap fixed, a texture seam fixed specifically on 2-top pairs, and a customer-drawn-over-their-own-seat ordering bug fixed. Also: the bathroom doorway gained real double-door artwork (the same doorway sprite system later reused for CHEF!'s kitchen door — see this file's own later entry on that), replacing a plain gap in the wall.
A dedicated dirty-dish-bin icon (stacked plates) placed next to a distinct trash-can icon at the kitchen wall, replacing whatever generic placeholder stood in for both before. Tile geometry made uniform across the whole grid — walls, counters, and floor tiles previously varied slightly in rendered size, now consistent everywhere. Camera zoom/pan added to the board view (the game no longer has to fit entirely inside the fixed canvas at 1:1).
The kitchen/counter wall run switched from individual flat-colored boxes to a real procedural autotile — seamless stone/brick texture, correct corner pieces, no visible gaps or seams at any join, and a safety cap on wall-run width so a very long run can't overflow its texture. Agents sharing a single grid cell (the congestion/passing mechanic later documented as Occupancy's 2-lane sharing) now visibly nudge to opposite sides of the tile and pass each other instead of overlapping. South-facing chair sprites had a flip/rotation fix (a south-facing chair was rendering mirrored or misrotated relative to the other three facings).
Applied the approved wall/table height mockup to every object: every station now sits on a visible plinth via one shared container change (no per-icon edits needed), and the whole draw order became Y-sorted (farther-back rows first, nearer rows last) since a fixed pass order can no longer guarantee correct occlusion once objects have height that extends into the row above them. Added a new house rule — no single table exceeds 2 seats, so every 4-top in the default layout is now two 2-tops physically pushed together (2x1) via a new Restaurant.pairTables(), merged into one bookable unit rather than two independently seatable halves.
Verified this session:
52/52 automated tests pass, including 4 new ones for the table-pairing rule.
A genuine mistake in the first Y-sort attempt — seated customers were pinned to always draw in front of their own table, which is backwards for a customer on the table's far side — was caught by the user looking at the actual screenshot, not by any test, and corrected. Worth remembering: this class of "internally consistent but wrong about visual intent" mistake needs a human eye on the image, not more automated checks.
Live-verified every station's raised plinth, the wall's brick-coursed thickness, all four table groups rendering as genuine 2x1 pairs, and correct far-side/near-side seating depth.
---
A note on Iterations 9-13 below:WORKLOG.md stops at the same point as this file did before this pass — "chair shape redesign," 2026-09-14 — even though progress/ holds 38 further screenshots (2026-09-14_09_... through 2026-09-15_46_...) documenting real, shipped work well past that point, and this project has no git history to fall back on either. There is no contemporaneous narrative for any of it — no "what was found, why, what broke" for this stretch, only the end-state screenshots themselves and their filenames. These five milestones are reconstructed from that evidence — each screenshot's actual pixel content checked against its filename and against current code, grouped into iterations by rough time-of-capture clustering — not from a WORKLOG entry the way every other milestone in this file is. Treat the "what changed" prose as inferred, not as a first-hand account; the screenshots themselves are genuine contemporaneous captures (not fabricated after the fact), just never linked or written up at the time. See the corresponding WORKLOG.md entry (2026-09-15, "documentation blackout found and PROGRESS.md reconstructed") for how this was put together.
Corrected the trash system per direct feedback: trash now comes from bussing a table (alongside the existing dirty dish it already produced), not from cooking, and the dumpster holds ~50 units before a TAKE_OUT_TRASH run empties it completely, rather than posting a run per single unit. Added a Bathroom station that generates routine trash and, less often, an actual mess needing a CLEAN_BATHROOM job — cleaning up a mess itself generates another unit of trash. Added two quality-of-life items to the counter-purchase catalog: a decorative Clean Dish Rack and a Dishwasher appliance that actually halves dish-washing time.
Verified this session:
48/48 automated tests pass, including 5 new ones covering the corrected trash source, dumpster capacity/emptying, bathroom occupancy-gated generation, and the dishwasher's real effect.
Two new tests initially failed from natural customer spawning interfering with an isolated test window — the same class of issue as an earlier queue test, fixed the same way (nextSpawnAt = Infinity) and now explicitly recorded as a pattern to recognize on sight.
Live-verified all three new visuals (an 80%-full dumpster, a messy bathroom, a placed Dishwasher) in one screenshot sent to the user.
Kitchen waste now has somewhere to go: cooking a dish generates a bag of trash, a TAKE_OUT_TRASH job carries it to a new Dumpster station outside (rendering closed/light/overflowing depending on how much has piled up), mirroring the existing dirty-dishes-to-sink flow. Staff now draw an ongoing wage ($/min, shown per-worker in the Staff list and as a total burn rate in Performance) deducted every 30 seconds, on top of the existing one-time hiring cost — money can go negative from payroll, a real cash-flow failure state rather than something clamped away. Started an ingredient system: src/sim/Ingredients.js catalogs the ingredients recipes already reference, shown in a new read-only Pantry panel, with a loose three-difficulty plan (INGREDIENTS_PLAN.md) for where this eventually goes — deliberately without implementing any stock/perishable/restocking rules yet, since none of those rules have actually been decided.
Verified this session:
45/45 automated tests pass, including 7 new ones covering payroll timing, negative-money cash-flow, trash generation/clearing, dumpster placement, and the ingredient catalog.
Forced the dumpster through all three fill states live and confirmed the art for each; ran the sim forward and confirmed a real payroll deduction with the correct computed amount and a log entry; confirmed the new Pantry panel and per-worker wage tags render with real data.
The five kitchen station icons were remodeled to actually look like their object (a fridge, a griddle with a sizzling patty, a cutting board with a knife, a service bell under a heat lamp, a sink with a faucet) after a direct check confirmed the earlier "graphics pass" had only polished each station's container, not the icon inside it. Built the game's first purchasing/placement system — previously only worker hiring had any cost mechanic — and used it to make a "Counter" a purchasable piece of furniture: buy it, click an empty tile to place it (Esc cancels, money isn't spent until placement actually lands), then click the placed counter to shop a small catalog of items for it (register, spice rack, napkin dispenser, potted plant). The sink and prep counter now render distinctly empty vs. actively in use.
Verified this session:
36/36 automated tests pass, including a new tests/furniture.test.js covering the purchase catalogs, Restaurant.removeStation, and resale-value rules.
Live-verified the full buy → place → shop-for-an-item flow, and forced station occupancy on/off via the console to confirm both the prep counter's and sink's empty/in-use art.
A UI testing gotcha was found and documented: the Inspector panel's innerHTML rebuilds every animation frame, so DOM refs into it can go stale between being found and clicked.
A large batch of rapid-fire follow-ups. Servers no longer stand on top of customers (a centralized Restaurant.serverStandingPointFor now picks a diagonal corner, never a seat — even an empty one); servers visibly carry the plate they're delivering; each recipe has distinct plate art; a vacated seat shows a dirty plate and a paid one shows money (both persisting after the customer object itself is gone); clean empty seats show a place setting. A full graphics fidelity pass brought floors, walls, and the exterior up toward RimWorld/Prison Architect style: wood-plank dining room vs. checker-tile kitchen vs. sidewalk/road outside, a decorative storefront facade and glass front door, a solid brick-coursed kitchen wall with a swinging double door, wood-textured tables, and chairs that rotate to face their table. Customers themselves now face whichever side of the table they're actually sitting on (front/back/profile pawn art) instead of one fixed silhouette. Customers arriving now form a real single-file queue on the sidewalk (capped there deliberately — never spilling into the road) instead of clustering wherever pathfinding happened to stop them. Cooks spawn in the kitchen; idle servers head to the door or the kitchen doorway instead of freezing in place; the pass sits right at the kitchen door as the pickup point.
Verified this session (see WORKLOG.md for full detail):
Three separate deadlocks found by simulation, not code review, each from a small feature request that looked safe in isolation: a server waiting to hand out menus could permanently block a party member's approach to a different seat at the same table; an early queue design had arrivals walk backward through everyone ahead of them; capping the queue to the sidewalk exposed a latent bug where the queue's own front slot sat on the one cell every escorted party must cross to reach the dining room. All three fixed with the same idiom (release an agent's occupancy hold once it's genuinely just standing still, not mid-task) and covered by regression tests.
A 600-simulated-second headless sweep (sim._tick in a loop, checking every agent's blockedTime) found zero agents stuck longer than 15 seconds after all three fixes, versus multiple agents stuck 40-50+ seconds before the last one.
A NaN-producing field-order bug in Simulation's constructor was found, fixed, discovered to break 6 tests that had come to depend on it, and deliberately reverted with a flagged follow-up task rather than silently masked.
32/32 automated tests pass, including 3 new regression tests for the deadlocks above and one for "a server's standing point is never a chair."
Historical note, kept for the record: the first pass at this backfill checked two plausible candidates, checkpoint-05-pawn-style-check.png and checkpoint-06-pawn-style-final.png, against actual pixels rather than filenames — checkpoint-05 turned out to be the pre-change "before" shot (same flat, pre-RimWorld icon style as checkpoint-04, Iteration 3's own screenshot) and checkpoint-06 a 100%-transparent blank capture (confirmed via the actual alpha channel, not by eye). Both were correctly ruled out at the time; the real match above was found in a later, finer-grained pass through the rest of progress/, not from either of those two.
Replaced emoji-based rendering with hand-drawn "bold and blocky" Canvas shapes (rectangular heads/bodies, black outlines, a chef hat or server apron as the only role cue) for every customer, worker, and station icon — no image assets. Seating changed from a fixed-point handoff to a literal escort: a server now physically walks each party to their table rather than just unlocking their movement. Tables are properly spread out (adjacent tables previously computed overlapping seat cells). A wall — built from ordinary, repositionable furniture, not permanent geometry — now separates the kitchen from the dining room, with a doorway. The default layout was rebuilt at ~2.5x its original floor area with a furniture-free cross-shaped walkway after an initial pass turned out to still have a hard chokepoint with no clearance around the door. Guests now arrive as Party groups (1-3 people) that must be seated together and never share a table with a different party, even if seats are free.
Verified this session (see WORKLOG.md for full detail):
28/28 automated tests pass, including 3 new tests specifically covering the party-exclusivity rule (seated together at distinct cells; a second party never offered a table already claimed; a table stays claimed until every member has left).
Balance retuned in three places to match the bigger layout and escort overhead (patience thresholds, SEAT_PARTY job priority, and the default starting crew in main.js) after live testing showed each one, in turn, collapsing throughput to near zero — not assumed correct from code review alone.
A real bug was found and fixed where any customer leaving a shared table posted a CLEAR_TABLE job unconditionally, even while other party members were still seated there.
Live UI screenshot confirms parties of varying sizes (1-3) seated at distinct tables simultaneously, with the event log showing party arrivals by name.
Customers no longer self-seat. They spawn at the far edge of a new outdoor waiting lane (visually distinct pavement), walk in and queue naturally up to the door, and wait there until a server claims a SEAT_CUSTOMER job, walks to the door, and seats them at a specific open seat. Tables now have real per-seat cells (up to 4 distinct grid cells around each table, each holding at most one customer) instead of a shared per-table counter, so occupants render at separate seats — with a bare-minimum chair icon marking every seat, filled or empty.
Verified this session (see WORKLOG.md for full detail):
A long-run (3000-tick) integrity check confirms no table ever exceeds its seat count and no seat cell is ever double-assigned.
Staffing still visibly matters with the new mechanic: 1 server + 1 cook served 6 (16 lost) vs. 2 servers + 2 cooks served 13 (11 lost) on an identical seed/layout over 300 simulated seconds.
All 25 automated tests pass (three needed updating for the new seating flow; see WORKLOG.md).
Two new deadlock-class bugs were found and fixed while building this (stale seating target, door-blocking queue point) plus a priority-starvation issue (a lone server could get stuck unable to ever clear a table because it was camped waiting to seat someone) — all documented in WORKLOG.md and DEVELOPMENT.md.
A small restaurant (entrance, 4 tables, fridge, prep counter, grill, pass, dish station) that the player can rearrange in a grid-based edit mode, then press Start and watch autonomous customers, servers, and cooks run the whole service loop with no direct control: spawn → wait for a table → seat → order → cook (through a data-driven recipe's steps) → deliver → eat → pay → leave, or abandon unhappy if patience runs out. Three data-driven dishes (Burger, Grilled Chicken, Salad). A management UI shows money, customer/order counts, a working/walking/idle staff breakdown, and an event log; clicking any agent opens a live debug inspector (state, task, path length, blocked time, stats). Simulation speed is adjustable (pause/1x/2x/4x); the RNG is seeded for reproducibility.
Verified this session (see WORKLOG.md for full detail):
Full customer lifecycle confirmed end-to-end through real UI interaction, not just code review.
Multiple customers served concurrently (14 in house at once in one live run).
Staffing visibly changes throughput: 1 server + 1 cook served 7/17 lost in a 300s run; adding a second server + cook under identical conditions served 19/0 lost.
Layout visibly changes throughput: a deliberately scattered kitchen layout collapsed a run from several served customers to 0 served under identical seed/staffing.
The in-editor drag-to-reposition workflow was tested with real pointer events (not just data-layer calls) — moved the Dish Station live, watched the grid and event log update, and confirmed the simulation kept running correctly afterward.
25/25 automated tests pass (tests/tests.html), covering recipe execution, order/customer state transitions, task assignment, payment calculation, pathfinding edge cases, and regression coverage for four deadlock bugs found and fixed while building this (see WORKLOG.md).
Known limitations and recommended next steps are in README.md and the session's final summary.