Go to Dishes and build your library. Each dish has:
- Name and meat type (pork, poultry, fish, beef, none)
- Difficulty (1–5) — how hard it is to cook
- Preference (1–5) — how much the family likes it
- Serves days (1–3) — a 2-day dish auto-generates a leftover day
You can also bulk-import from CSV (Polish or English column names).
In Settings → Tags, create tags like "nanny", "takeout". Tags can have rules:
- Max per week — e.g. nanny meals max 2×/week
- Min gap days — e.g. takeout at least every 14 days
Assign tags to dishes in the dish form.
Go to New plan, pick a date range, and click Generate. The genetic algorithm runs in the background and produces an optimized meal schedule respecting all constraints. You can fine-tune per-day difficulty limits and cumulative difficulty budgets before generating.
On the plan detail page:
- Click the 📌 on any day card to pin/unpin its current dish in one tap — no need to open the day
- Click any day card to open it and pick a different dish, or mark the day as skip
- Click ✏️ next to the plan name to rename the plan
- Click Regenerate — unlocked future days are regenerated, past days and pinned days stay
- Month boundaries are visually marked in the calendar
- Past days are collapsed by default; use Show N past days above the calendar to reveal them (they're excluded from printing either way)
- A day whose dish exceeds that day's difficulty cap shows the excess as extra "overflow" segments on the difficulty bar
Click Continue on any plan to create a follow-up. Select a date range from the source plan to carry over (those days become locked in the new plan), set the new end date, and generate.
- Print — click Print on the plan detail page for a print-friendly view (save as PDF from the browser)
- Calendar (.ics) — from the plan detail page's overflow menu (⋮), download an ICS file with one all-day event per cooking day, ready to import into Google/Apple/Outlook calendars
- JSON backup — in Settings, download all data (dishes, plans, tags) as a JSON file or copy a compressed share link
Meal planning
- Genetic algorithm generates optimized schedules for any date range
- Hard constraints: difficulty caps, tag requirements, tag weekly limits, tag min gap
- Soft constraint: same-meat rule (strength adjustable in Settings — strict/moderate/relaxed/off)
- Soft preferences: family ratings, dish variety, repeat penalties, meat diversity (Shannon entropy)
- Pin any day manually — regeneration respects locked meals
- Cumulative difficulty budgets for date ranges
Calendar view
- 7-column weekly grid with configurable first day of week (Mon/Sun)
- Weekends highlighted, meat type emoji next to dish name
- Month boundary banners with realigned grid
- Per-day difficulty cap shown on each card as a filled/unfilled bar, leftovers labelled
- One-tap pin/unpin directly from the calendar; past days collapse by default and are never printed
Dish library
- Full CRUD with meat type, difficulty (1–5), family preference (1–5), serves days (1–3)
- Tag system with optional per-week limits and minimum gap constraints
- Bulk import from CSV (Polish or English column names)
Plan continuation
- Select any date range from a source plan to carry over
- Carried days are locked; GA generates the rest
Day modifiers
- Set per-day difficulty cap overrides directly on the plan generator
- Modifiers persist and are respected by every regeneration
Export & sharing
- Print / save as PDF — browser print dialog, print-optimised layout
- Calendar (.ics) export — one all-day event per cooking day (leftover/skipped days excluded), from the plan overflow menu
- Full JSON backup — includes dishes, plans, tags, family name, settings
- Share via compressed URL (copy to clipboard)
- Import JSON restores everything including settings
Themes
- Trattoria della Famiglia (default) and PRL (Polish People's Republic canteen) — switchable in Settings
PWA
- Installable on Android and desktop
- Offline-capable (app shell + assets cached by service worker)
- Vite 7 + React 19 + TypeScript
- Zustand (state), Zod (validation), React Router (hash routing)
- Web Worker + Comlink — GA runs off the main thread
- pako — compressed share links
- vite-plugin-pwa — service worker, manifest
npm install
npm run dev # http://localhost:5173/basil-cooking-planner/
npm test # Vitest unit tests
npm run test:e2e # Playwright e2e (needs app running)
npm run build- Algorithm description — how the genetic algorithm generates meal plans (with mermaid diagrams)
- Pushes to
maintrigger GitHub Actions → tests + build → deploys to GitHub Pages - Tests also run on every PR via a separate CI workflow
