Your week
Tap an empty slot to choose a meal. Tap a filled one to read the recipe. Everything saves to this browser automatically.
Rotation
How many different meals do you want in each slot this week? A low number means less shopping and less thinking, and more repetition — two breakfasts across seven days means eating each one three or four times. Because a short rotation multiplies whatever it contains, choosing well matters more as the number falls. So the planner takes the most protein-dense meals available, subject to two rules: no protein source may fill more than half a rotation, which at two meals forces two different sources; and the week must hold at least two oily-fish servings for omega-3, which protein density alone would never choose, because oily fish costs more calories per gram of protein than cod does.
You can also name the meals yourself. A choice is a pin, not a filter: pick two of five dinners and the planner still fills the other three by protein density, ranking around your choices rather than over them. The limit is the rotation number itself — there is only one idea of how many meals a slot holds, so the chooser stops at it. A meal you pinned is never displaced, not by the half-rotation cap and not by the omega-3 rule; the report tells you when your choice has overruled one of them, because a rule that bends silently is a rule you cannot trust.
Saved weeks
Every time you build a week it is saved here, dated. Editing a slot changes the week you are living in; building a new one starts a new record. Restoring copies an old week forward rather than reopening it — history you can edit is not history, and the point of an archive is to tell you what you actually ate.
Shopping list
A snapshot of the week you built it from, not a live view of it — so it cannot rewrite itself while you are standing in the shop. Grouped by aisle. Tick what you already have and the ticks persist. Dinner quantities feed four; breakfast and lunch feed you alone. Where a recipe needs part of a tin, the list buys the whole tin and shows the shortfall.
Recipes
Forty-five meals, ranked by the share of their calories that come from protein. Tap any card to read it. Breakfast and lunch serve one; dinners serve four and carry a note on splitting them for the children.
Ingredients
Your opinions about food, as data. This is a weighting layer over the forty-five recipes, not a separate list — a stance changes how the planner scores every meal containing that ingredient, and Banned removes those meals from the planner and the picker entirely. A meal's adjustments are summed and capped at ±20 points, because preference should tilt the ranking, not overturn it: protein density runs 21 to 63 across the library, and four liked ingredients should not outrank cod on sentiment alone.
Stances live in ingredients.js, so ask me to add an ingredient and its reasoning there and it becomes permanent. Changing a stance here is a local experiment, marked as such, and reversible.
Within each stance the best food comes first, and “best” is computed rather than chosen: protein density leads, so cod heads Loved and quark follows it. But a food carrying under 5g of protein per 100g is not a protein source and does not compete on that scale — those sort by fewest calories per 100g, because once a food gives you no protein the only benefit left is how little it costs. Asparagus therefore sits above avocado, and avocado above olive oil.
The tags beside each name are derived from the numbers, never typed. Tier 1 means 55% or more of the food's calories arrive as protein, Tier 2 is 30 to 55%, Tier 3 is below 30 — an accent, not a base. A food is only tiered once it carries at least 5g of protein per 100g; below that it reads Trace protein, because a mushroom computes to 55% and is not cod. Eat freely is under 40 kcal per 100g and Calorie-dense is 400 or more, because calorie density is a property of the food. Carb-heavy is measured differently — 20g of net carbs per 100g for things you weigh, but 15g per item for things you count, because carbohydrate is spent from a daily budget one serving at a time. A crispbread is 60g of carbs per 100g and 6g per slice, and only the second number is one you ever eat. Only Omega-3, High fibre, High sodium and Ultra-processed are declared by hand, because no arithmetic on protein, carbs and calories can tell you a sardine has omega-3.