Crafting
Usage guide of craft.recipes: recipes with inputs, outputs and a time, made by hand or at stations, locked recipes, the craft screen, the recipes collection, settings and defaults, service, events, hooks and verbs.
Crafting recipes (craft.recipes) #
What it is for #
craft.recipes turns items into other items. A recipe lists inputs, outputs and a time, and is made by hand or at a station of the world (a workbench, a forge, a kitchen, a printer). Recipes can start locked and be unlocked by a script, a mission or a find. A craft screen lists what can be made with what the player holds. Inputs are taken from inventory.items when the craft starts; the outputs are given when the time is over, and what does not fit in the inventory is owed and given as soon as there is room. One craft runs at a time.
Turn it on #
Install the kit in a project and set its settings with the tools below; gripforge kit api craft.recipes lists every setting, and gripforge docs craft-recipes prints this guide offline.
gripforge_gamekit_install { project_id: "gkp_…", id: "craft.recipes" }
gripforge_gamekit_configure { project_id: "gkp_…", id: "craft.recipes",
config: { "handCrafting": true, "stationReach": 5 } }
{ "id": "gem", "name": "Gem", "station": "forge", "inputs": [{ "item": "plank" }], "outputs": [{ "item": "gem", "count": 7 }], "seconds": 0.5 }
First example #
<!-- test: kits/game_engine/host/tests/craft_recipes.rs::a_craft_takes_inputs_runs_at_its_station_and_owes_what_does_not_fit --> With two wood, craft makes two planks at once. A recipe with a station is refused (station) until its station is open; the timed craft then blocks others (busy), survives a save, and gives its outputs at the end, owing what the inventory cannot hold.
craft.recipes.craft("plank") // { ok: false, reason: "inputs" }: no wood yet
inventory.items.give("wood", 2)
craft.recipes.craft("plank") // { ok: true }: two planks at once
craft.recipes.craft("gem") // { ok: false, reason: "station" }: it is made at a forge
craft.recipes.open("forge", station) // true: the station (an instance with craft_station) is open
craft.recipes.craft("gem") // { ok: true }: craft.started, the gems come after 0.5 s
craft.recipes.craft("plank") // { ok: false, reason: "busy" }
Settings and defaults #
| Setting | Default | Meaning |
|---|---|---|
handCrafting | true | {{s_handCrafting}} |
stationReach | 4 | {{s_stationReach}} |
stationLabel | Use {name} | {{s_stationLabel}} |
Services #
craft.recipes(service):recipes(station?),canCraft(id),craft(id)answers{ ok, reason? },unlock(id),unlocked(id),open(station?, entity?),close(),current()andjob()(the running craft).- The
recipescollection:id,name,description,category(a heading on the craft screen),station(the kind of station, absent: by hand),inputs(1 to 12 stacks{ item, count }),outputs(1 to 6 stacks),seconds(0 to 3600, default 0: at once),unlocked(falsehides it until unlocked, defaulttrue). A recipe{ "id": "iron_sword", "extends": "sword" }of a game or a mod inherits an entry. An instance with the componentcraft_station { station, label? }is a station of that kind; using it opens the craft screen with the recipes made there.
Events #
craft.started: the inputs were taken; the outputs come afterseconds.craft.completed: the outputs were given (recipe,outputs).craft.failed: a craft was refused, with areasonofunknown,locked,station,inputs,busy, or the reason of the tap that cancelledcraft.make(refusedwhen it gave none).craft.unlocked: a locked recipe was revealed (recipe).craft.opened(the craft screen opened;stationis empty for the hand menu) andcraft.closed.
Hooks and modding #
craft.make: the player is about to make a recipe (it is known, makeable here, nothing else runs, the inputs are held, nothing taken yet);secondsis mutable (a craft from thecraft_itemverb stays instant), and cancelling answers{ ok: false, reason }and emitscraft.failed.craft.unlock: a locked recipe is about to be revealed (unlock, theunlock_recipeverb); cancelled, it stays locked (unlockanswersfalse, no event).
{ "id": "slow_forge", "hook": "craft.make", "match": { "station": "forge" }, "set": { "seconds": 5 } }
Using it from content #
Script verbs: the actions craft_item (recipe: make it for the player at once, no station needed), unlock_recipe and open_crafting (station, empty for the hand menu), and the condition recipe_unlocked. The input craft_menu (key KeyG) opens the hand menu. Variables: craft.open, craft.station, craft.crafted.
{ "craft_item": "bandage" }
{ "unlock_recipe": "steel_pickaxe" }
{ "open_crafting": "workbench" }
When it does not do what you expect #
| Symptom | Cause and fix |
|---|---|
craft answers ok: false with a reason | unknown (no such recipe), locked (call unlock), station (open the right station first), inputs (the player lacks items) or busy (another craft runs). |
| The outputs never arrive | The inventory is full: what does not fit is owed and given as soon as there is room. A timed craft also needs the game to be playing for its seconds to elapse. |
| A recipe does not show on the craft screen | It is locked (unlocked: false), its station is not the one open, or handCrafting is false for a hand recipe. |
Limits #
- It needs
inventory.items: there is no crafting without an inventory. - One timed craft at a time, for the player only; no queue and no skill or quality system.
- The craft screen is a web display module; on other targets the service, the verbs and the events work and your game draws its own screen.
Versions #
Kit craft.recipes 1.2.1. It needs inventory.items, input.actions and game.engine ^1. 1.2.0 made recipes an inheritable registry (extends); 1.1.0 added the hooks; 1.0.0 (2026-10-04) was the first release.