A modern, progressive web app for managing and cooking from your recipe collection. Built with Svelte and Vite, Soustack provides an elegant interface for browsing recipes, scaling ingredients, organizing your cooking workflow, and managing shopping lists—all while working offline.
Cooking from digital recipes can be frustrating: ingredients are hard to scale, instructions get lost in long pages, and shopping lists require manual copying. Soustack solves these problems by providing:
- Ingredient Scaling: Instantly adjust recipe quantities for any number of servings with automatic calculations
- Mise en Place Mode: Organize ingredients by cooking technique to streamline your prep work
- Shopping List Management: Combine ingredients from multiple recipes and export directly to Google Tasks
- Offline Access: Install as a Progressive Web App (PWA) and access your recipes without an internet connection
- Clean, Fast Interface: Modern component-based UI that makes recipe browsing and cooking enjoyable
Whether you're cooking for one or hosting a dinner party, Soustack helps you stay organized and focused on what matters: great food.
├── public/
│ ├── recipes/ # All recipe JSON files
│ ├── recipes-index.json # Lists recipe filenames to load
│ ├── data/techniques.json # Technique glossary used in Mise en Place mode
│ ├── images/ # Recipe images & docs
│ ├── manifest.json # PWA manifest
│ ├── service-worker.js # Offline caching & runtime recipe cache
│ └── icon-192.png, icon-512.png
├── src/
│ ├── App.svelte # Main layout + filtering + shopping list actions
│ ├── app.css # Global styles
│ ├── main.js # Mounts Svelte app + registers service worker
│ └── lib/
│ ├── components/ # Header, cards, scaling controls, shopping modal, etc.
│ ├── stores/ # recipes, UI, scaling state
│ └── utils/ # scaling math, formatting, parsing, shopping + Google Tasks helpers
└── vite.config.js # Adds `base` handling for GitHub Pages mode
npm install
npm run dev # starts Vite on http://localhost:5173The dev server hot-reloads Svelte components, fetches JSON from public/, and runs entirely client-side.
Soustack now reads site- and deployment-specific settings from the root-level config.js. Edit this file to personalize a clone (title, owner name, feature toggles, etc.) without touching the core UI code. An example config.richard.js is included to show how a branded instance (e.g., “Richard's Recipe Collection”) can override the defaults—copy it or use it as inspiration for your own deployment.
| Path | Description | Default |
|---|---|---|
site.title |
Base application name used when no owner is set | Soustack |
site.owner |
When set, header + document title become "{owner}'s Recipe Collection" |
null |
site.tagline |
Optional subtitle beneath the header | Your recipes, organized. |
site.logoUrl |
Optional logo shown in the header | null |
features.enableScaling |
Enables the servings stepper + ingredient scaling UI | true |
features.enableSharing |
Shows the per-recipe “Share” action | false |
features.enableImport |
Placeholder for future import flows | true |
theme.primaryColor |
Overrides the accent color used throughout the UI | null |
theme.fontFamily |
Custom font stack applied to the body text | null |
data.storageKey |
Local storage key reserved for future persistence | soustack-recipes |
branding.showAttribution |
Controls whether the footer shows “Made with Soustack” | true |
branding.repoUrl |
Link target for the attribution footer | https://github.com/yourusername/soustack |
Changes take effect immediately in dev. For deployments, update config.js before building so the correct branding ships with the bundle.
| Command | Description |
|---|---|
npm run build |
Standard Vite build (base /) for Vercel or any static host |
npm run build:ghpages |
Builds with --mode ghpages, setting base to /soustack/ |
npm run deploy:ghpages |
Builds with the GitHub Pages base and publishes dist/ via gh-pages |
npm run preview |
Serves the production build locally |
npm run preview:ghpages |
Builds+serves with the /soustack/ base so you can spot-check Pages locally |
Use the default build command (npm run build) and set the output directory to dist/. Vercel will serve the app at the root path.
- Run
npm run deploy:ghpageslocally (requiresgh-pagesto have push access). - Ensure the Pages project is configured to serve from the
gh-pagesbranch. - The custom
baseinvite.config.jsautomatically rewrites absolute asset URLs to/soustack/...during thebuild:ghpagescommand, so routing works under the repository subpath.
The shopping list modal can push combined ingredients directly to Google Tasks. Configure the OAuth client ID by editing the inline script in index.html:
<script>
window.GOOGLE_TASKS_CLIENT_ID = "123456789-your-client-id.apps.googleusercontent.com";
</script>The client ID is safe to commit. The export button loads the Google Identity script on demand, requests the tasks scope, creates a dedicated task list, and populates the merged ingredient lines as tasks.
- Recipes are stored as JSON files in
public/recipes/. Updatepublic/recipes-index.jsonwhenever files are added or removed. - Any images referenced inside the recipe JSON should live under
public/images/(paths are relative to the site root). public/service-worker.jsprecaches the shell (index.html, manifest, data files) and runtime caches recipe JSON for offline browsing. The worker automatically respects the base path so it works on both deployments.- The manifest plus icons keep the site installable. Update the placeholder icons in
public/if you have branded artwork.
npm run dev– verify filtering, scaling, and modal interactions locally.npm run build && npm run preview– smoke-test the production bundle.npm run build:ghpages– confirm the GitHub Pages build compiles.npm run preview:ghpages– simulate the/soustack/base locally (runsbuild:ghpagesunder the hood).
Feel free to iterate on the Svelte components or add new ones—state is centralized in the stores under src/lib/stores, so UI composition stays straightforward.