2026 10 13 crafting design - xopherdeep/do-it-for-the-xp GitHub Wiki
Date: 2026-10-13. Status: design approved in chat by the owner, section by section; this spec awaits review.
Beasts should drop things, and heroes should craft with them, the way Animal Crossing does it: nothing can be made until its DIY recipe has been learned. The Kitchen cooks the 33 favorite foods; the Workbench makes battle goods, accessories, bag and storage upgrades and furniture. It must work with no setup: no Game Master writes drop tables.
The Workbench (MyCrafts) and the Kitchen (MyFoods) exist today with placeholder data (a remote accessory fetch and
a mock food list). The bag already has a material kind (src/lib/services/inventory/Inventory.ts).
- Approach A: one built-in catalogue. Drops are a pure function of the beast's temple theme, the fight's difficulty and the beast's rank. Family-made beasts work because they carry a theme. No per-beast loot tables.
- Food is in-game only. Cooked food restores HP/MP; a hero's own favorite food restores double. Real treats stay GP shop items (the rewards-vs-powers rule).
- The Workbench makes all four: battle goods, accessories with stats, bag and storage upgrades, furniture. Placing furniture in My Home is a later epic with its own spec; furniture can be crafted and stored now.
- Recipes come from beast drops, region shops, and temple chests and boss first-clears. No starter recipes; instead a hero's first victory always drops a recipe card.
- Loot from a quest that waits for approval waits with it. Free fights drop commons and ingredients only.
- The Workbench tab "Weapons" is relabelled "Battle". The only tab change; every other tab keeps its label.
Every temple theme (TEMPLE_THEME_KEYS) has one common material (the fodder) and one rare.
| Theme | Chores | Common | Rare |
|---|---|---|---|
| wind | quick chores | Feather | Zephyr Plume |
| earth | yard and pets | Wood | Amber |
| water | bathroom | Spring Water | Pearl |
| fire | cooking and big jobs | Coal | Fire Opal |
| ice | laundry and fridge | Cloth | Frost Crystal |
| light | school | Paper | Star Fragment |
| shadow | kitchen | Iron Nugget | Onyx |
| moon | bedtime and self-care | Herb | Moonstone |
| storm | bedroom and clutter | Stone | Thunder Egg |
Ingredients (the pantry, 10). Themed drops, and all ten are sold at the Home Town market for 5 GP each.
| Theme | Ingredients |
|---|---|
| shadow | Flour, Sugar |
| ice | Milk, Cheese |
| earth | Egg, Veggies, Fruit |
| fire | Meat, Spice |
| water | Fish |
wind, light, moon and storm drop no ingredients.
Bag rows: { id: "<material-id>", name, kind: "material", qty, faIcon } (ingredients use the same kind, so the
Pantry and My Goods' Materials tab both find them).
rollDrops(input, rng) in src/lib/services/crafting/drops.ts, pure, rng defaults to Math.random and tests pass
a seeded one. Input: the defeated beasts (each { theme?, element?, isBoss, type, elite }), the fight kind
(free or not), the difficulty, and whether this is the hero's first victory. Each beast rolls on its own; the
results merge into stacks.
Theme. The beast's theme; without one, its art element: wind→wind, earth→earth, water→water, fire→fire,
ice→ice, light→light, shadow→shadow, moon→moon, lightning→storm; anything else→wind.
Difficulty. A quest fight uses the quest's Fibonacci difficulty; a non-free fight with no quest uses 3.
| Drop | Quest and temple fights | Free fights |
|---|---|---|
| Common of the theme | difficulty 1-2: 1, 3-7: 2, 8-12: 3, 13+: 4; +1 miniboss, +2 boss | 1 |
| Ingredient (themes that have them) | 50% for 1; difficulty 5+: 1 for sure; 8+: 2 | 50% for 1 |
| Rare of the theme | boss 100%, miniboss 35%, elite 20%, plain 0 | never |
| Recipe card | boss 50%, miniboss 25%, elite 15%, plain 6% | never |
First victory. When the hero knows no recipe and holds no recipe card, the fight drops one recipe card for sure, whatever its kind.
Which card. A random recipe whose sources include a drop of that theme, preferring ones the hero neither knows nor holds. When every one is known, any of them (a duplicate, sold for GP).
Where loot lands. The bag, then Storage; what fits nowhere is left behind and the victory line says so.
When loot pays.
- A fight with no approval wait: at the win, beside XP/GP/AP (
useBattleOutcome.settleFightandsettleQuestWin). - A quest held for approval: the win stores the roll input on the pending claim (
lootRoll: themes, ranks, difficulty, first-victory flag) and the Game Master's approval rolls and pays it, with a notification. - Only battles drop. A quest completed off the battlefield drops nothing.
Enemies carry their theme. Enemy (src/lib/services/battle/battleService/types.ts) gains theme? and
elite?, copied by the encounter loader from the beast (elite = the encounter used the beast's variantAvatar).
The victory dialog lists the loot under the rewards: "Wood ×2 · Egg · DIY: Pizza".
-
knownRecipes: string[]on each hero (persisted with the profile). Old saves start empty. -
Recipe cards are bag rows
{ id: "recipe:<recipeId>", name: "DIY: <Name>", kind: "misc", type: "recipe", recipeId }. They list under Misc in My Goods (no new tab), with a Learn button. - Learn: the card is used up and the id joins
knownRecipes. A card already known shows Sell for N GP instead. - Sell price: half the recipe's shop price; a recipe with no shop price sells for 20 GP (drop) or 60 GP (chest).
- Unknown recipe ids in
knownRecipesare ignored. Unknown recipes are never shown on the stations.
src/lib/services/crafting/crafting.ts, pure:
-
craftable(hero, recipe, qty): whether the materials are there, counted across the bag and Storage, and whether the output has room. -
craft(hero, recipeId, qty): new bag and Storage rows, or a refusal line. Materials come from the bag first, then Storage (reuseStorage.ts:rowsAfterTaking,canCarry). The output goes to the bag, else Storage, else refuse ("Your bag and storage are full."). - Recipes need materials and ingredients only, never another crafted item.
Screen pattern for both stations:
- Rows of known recipes for the active tab: the product, then the needs line
Wood 3/5 · Iron Nugget 1/2. Craftable rows are bright; the others dimmed. - Tapping a row opens a bottom sheet (thumb reach): needs with have/need, a quantity stepper, Craft / Cook.
- The header meta reads
23 / 75 recipes. An empty station says where recipes come from: "Defeat beasts to find DIY recipes." - Sounds through
play$fx; toastsrpg-toast, position middle.
Tabs stay: All | Favorites | Meals | Snacks | Desserts | Pantry. Favorites pins the hero's own favoriteFood;
Pantry lists the ingredients held. FOOD_OPTIONS stays the one list of foods; the catalogue adds each food's
category and needs.
| Food | Kind | Needs |
|---|---|---|
| Apple | snack | Fruit 2 |
| Bacon | snack | Meat 1, Spice 1 |
| Bread | snack | Flour 2 |
| Burger | meal | Meat 1, Flour 1, Veggies 1 |
| Burrito | meal | Flour 1, Meat 1, Veggies 1, Cheese 1 |
| Cake | dessert | Flour 1, Sugar 2, Egg 1, Milk 1 |
| Candy Cane | dessert | Sugar 2 |
| Candy Corn | dessert | Sugar 1, Veggies 1 |
| Carrot | snack | Veggies 2 |
| Cheese | snack | Milk 2 |
| Cheeseburger | meal | Meat 1, Flour 1, Cheese 1, Veggies 1 |
| Coffee | snack | Spice 1, Milk 1 |
| Cookie | dessert | Flour 1, Sugar 1, Egg 1 |
| Corn | snack | Veggies 1, Spice 1 |
| Croissant | snack | Flour 2, Milk 1 |
| Drumstick | meal | Meat 1, Spice 1, Flour 1 |
| Egg | snack | Egg 2 |
| Fish | meal | Fish 2, Spice 1 |
| French Fries | snack | Veggies 2, Spice 1 |
| Fried Egg | snack | Egg 1, Spice 1 |
| Hotdog | meal | Meat 1, Flour 1 |
| Ice Cream | dessert | Milk 2, Sugar 1 |
| Lemon | snack | Fruit 1, Sugar 1 |
| Pepper | snack | Veggies 1, Spice 2 |
| Pie | dessert | Flour 1, Fruit 2, Sugar 1 |
| Pizza | meal | Flour 1, Cheese 1, Veggies 1 |
| Popcorn | snack | Veggies 1, Milk 1 |
| Salad | meal | Veggies 2, Fruit 1 |
| Sandwich | meal | Flour 1, Meat 1, Cheese 1 |
| Sausage | snack | Meat 2 |
| Smoothie | snack | Fruit 1, Milk 1 |
| Steak | meal | Meat 2, Spice 1 |
| Taco | meal | Flour 1, Meat 1, Spice 1, Veggies 1 |
Source. Every food recipe drops from beasts of the theme of its first ingredient (Pizza: shadow, the kitchen).
Effects (src/lib/services/crafting/foodEffects.ts): snack +20 HP; meal +40 HP and +15 MP; dessert +30 MP;
capped at max. The hero's own favoriteFood (matched on the singular name, as MyFoods already does) restores
double. Cooked food is a consumable bag row; it can be eaten from My Goods and from the battle bag's Goods sheet
(the same sheet that drinks potions, BattlePotions.ts).
Tabs: All | Furniture | Accessories | Battle (was Weapons) | Key. The remote xp_accessory fetch goes away.
Battle (8). Potions use the existing POTIONS rules. Bombs are one-shot goods with no MP cost: they run an
existing BattleEffectId and are used up.
| Recipe | Needs | Source |
|---|---|---|
| Potion | Herb 2, Spring Water 1 | drop moon; shop hometown-market 40 GP |
| Ether | Spring Water 2, Feather 1 | shop wrecked-ship 60 GP |
| X-Potion | Herb 3, Spring Water 2, Amber 1 | shop witchs-hut 150 GP |
| Mega Potion | Herb 4, Spring Water 2, Pearl 1 | chest water |
| Elixir | Herb 3, Moonstone 1, Pearl 1 | chest moon |
Ember Bomb (kindle) |
Coal 3, Paper 1 | shop crystal-caverns 80 GP |
Frost Bomb (frost) |
Spring Water 2, Cloth 1, Iron Nugget 1 | shop snow-shack 80 GP |
Spark Bomb (stun) |
Stone 2, Iron Nugget 1, Feather 1 | shop cloud-market 80 GP |
Accessories (9). Each needs its theme's rare; all come from chests of that theme.
| Accessory | Needs | Bonus |
|---|---|---|
| Zephyr Charm | Zephyr Plume 1, Feather 5 | +3 speed |
| Amber Amulet | Amber 1, Wood 5 | +10 max HP |
| Pearl Ring | Pearl 1, Spring Water 3 | +10 max MP |
| Fire Opal Ring | Fire Opal 1, Coal 5 | +3 strength |
| Frost Brooch | Frost Crystal 1, Cloth 5 | +3 defense |
| Star Pendant | Star Fragment 1, Paper 5 | +5 max HP, +5 max MP |
| Onyx Band | Onyx 1, Iron Nugget 5 | +2 strength, +2 defense |
| Moonstone Locket | Moonstone 1, Herb 5 | +15 max HP |
| Thunder Bracer | Thunder Egg 1, Stone 5 | +2 speed, +2 strength |
Key (7): upgrades apply the moment they are crafted (no bag row). Tier n needs tier n-1; a tier the hero already has (bought or crafted) shows as built.
| Recipe | Effect | Needs | Source |
|---|---|---|---|
| Bigger Pouch I | bag 30 stacks | Cloth 5, Feather 3 | shop hometown-market 60 GP |
| Bigger Pouch II | bag 40 | Cloth 8, Wood 4 | shop pegasus-ranch 120 GP |
| Bigger Pouch III | bag 60 | Cloth 10, Iron Nugget 5, Frost Crystal 1 | shop cloud-market 250 GP |
| Storage Chest I | STORAGE_TIERS[0] |
Wood 6 | shop hometown-market 80 GP |
| Storage Chest II | STORAGE_TIERS[1] |
Wood 10, Iron Nugget 3 | shop hermits-tent 150 GP |
| Storage Chest III | STORAGE_TIERS[2] |
Wood 12, Iron Nugget 6, Stone 4 | shop pond-of-life 300 GP |
| Storage Chest IV | STORAGE_TIERS[3] |
Wood 15, Iron Nugget 8, Onyx 1 | shop theia-city 600 GP |
The bag size becomes per hero: bagTier (0 = 20 stacks, the old BAG_STACKS). Storage chests set the same
storageTier the Gold Bank sells, so buying and crafting are two ways to one upgrade.
Furniture (18). Two per theme: a plain piece (drop of the theme) and a centrepiece with the rare (chest of the
theme). Crafted furniture is a misc bag row { furniture: true } and is kept in the bag or Storage until the My
Home epic lets it be placed.
| Theme | Plain (drop) | Centrepiece (chest) |
|---|---|---|
| wind | Feather Pillow: Feather 6, Cloth 2 | Wind Chime: Zephyr Plume 1, Feather 4, Iron Nugget 1 |
| earth | Log Stool: Wood 6 | Amber Lamp: Amber 1, Wood 4 |
| water | Fish Bowl: Spring Water 4, Stone 2 | Pearl Mirror: Pearl 1, Spring Water 2, Iron Nugget 2 |
| fire | Coal Stove: Coal 4, Iron Nugget 2 | Fire Opal Hearth: Fire Opal 1, Stone 4, Coal 2 |
| ice | Rag Rug: Cloth 6 | Frost Chandelier: Frost Crystal 1, Iron Nugget 3 |
| light | Bookshelf: Paper 4, Wood 4 | Star Globe: Star Fragment 1, Paper 2, Iron Nugget 1 |
| shadow | Pot Rack: Iron Nugget 5 | Onyx Clock: Onyx 1, Wood 2, Iron Nugget 2 |
| moon | Herb Planter: Herb 4, Stone 2 | Moonstone Nightlight: Moonstone 1, Cloth 2 |
| storm | Toy Chest: Wood 3, Stone 3 | Thunder Lamp: Thunder Egg 1, Iron Nugget 2 |
Total: 33 foods + 8 battle + 9 accessories + 7 key + 18 furniture = 75 recipes.
Nothing applies Accessory.bonusStats today. Each hero gets one equipped accessory (the bag row moves into the
slot; unequipping moves it back). Its bonus adds to the hero's strength, defense, speed, max HP and max MP wherever
the battle reads them: one place, found in src/lib/services/stats/ (StatEffects / EngineStatsService), not per
screen. The slot shows in the equipment modal beside the hands. No nav bar changes.
- Boss first-clear of a temple drops one recipe card whose sources include a chest of that temple's theme (unknown preferred), in the boss chest beside the usual reward.
-
Temple creator: a chest's loot picker (
RoomLootConfig) can also hold a recipe card or a material from the catalogue. Optional; nothing breaks when a GM never uses it. -
Shops:
ShopItemTypegainsRecipeandIngredient. Region shops are stocked from the catalogue's shop sources by merging into the defaults (ShopsDb.seedDefaults/syncWithRegistry): a family's own shelves are never removed. Buying a recipe puts the card in the bag; buying an ingredient puts it in the bag.
src/lib/services/crafting/
catalog/materials.ts MATERIALS (commons, rares, ingredients: id, name, kind, theme, faIcon)
catalog/recipes.ts RECIPES (id, name, station, tab, makes, needs, sources, shopPrice?), foods built from FOOD_OPTIONS
drops.ts rollDrops, themeOf
recipeBook.ts learn, sell, knownOf
crafting.ts craftable, craft
foodEffects.ts foodGain(food, hero)
user.ts gains knownRecipes, bagTier, accessory (persisted in profileFields.ts) and the actions
addLoot, learnRecipe, sellRecipeCard, craftRecipe, equipAccessory.
- Catalogue integrity (jest): every need names a material; all 33
FOOD_OPTIONShave a recipe; every recipe has at least one source; every theme has at least one drop recipe; every shop source names a real shop id; 75 recipes. - Drops: seeded rolls for each rank and kind; first-victory guarantee; unknown-first card choice; theme fallback.
- Recipe book and crafting: learn, duplicate sell, craft from bag then Storage, full bag refusal, tiered upgrades.
- Food: favorite doubles; caps at max.
- One Cypress run (
--browser chrome): win a fight, a card drops, learn it, craft a Potion, drink it in battle.
- Catalogue and integrity spec.
- Drop engine.
- Recipe book, crafting engine, hero state.
- Loot on battle wins and on approvals (Enemy theme/elite, victory lines,
lootRollon held claims). - Chests, boss first-clears, shop stock.
- Kitchen screen and food effects (My Goods eat, battle Goods sheet).
- Workbench screen (Battle tab, Key upgrades and
bagTier, bombs in the Goods sheet). Waits for board #1285. - Accessory slot with stats in battle.
- E2E loop.
- Later epic, own spec: placing furniture in My Home.
Per-beast loot overrides; gifting food to the party; trading between heroes; look pieces as drops (Look Unlocks
project 3 can add a drop kind to rollDrops later); placing furniture.