HOW TO MAKE A GPC GAME ====================== A GPC game is ONE JSON file. There's no code: the GPC engine reads the file and runs the game. You describe resources, the buttons players click, buildings, crafting recipes and upgrades, and the engine does the rest. If you're an AI helping someone make a game: read this whole file, ask the person what their world is about (or invent something delightful if they say "surprise me"), then reply with ONLY the finished JSON in one code block. Follow every rule in "RULES THE ENGINE CHECKS" below, or the game won't load. HOW THE GAME PLAYS ------------------ - Every resource has an amount and, optionally, a storage cap. - Actions are buttons the player clicks for a small, instant reward. That's how the game starts. - Buildings are bought with resources. Each copy costs more than the last (cost x costRatio per copy owned). Buildings can: produces - add resources every second consumes - use up resources every second (e.g. a factory eats ore) capBonus - raise a resource's storage cap If a building's input runs short, it slows down and makes proportionally less. Players can switch consuming buildings on and off. - Crafts are one-shot recipes: pay a cost, get resources right away. - Upgrades are bought once each and multiply a building's output or a resource's storage. - Everything except the starting resource/action stays hidden until its "unlock" condition is met, so the game unfolds gradually. Once something appears it stays visible. - The game is won by buying the upgrade named in "goal". - Progress keeps running while the player is away (up to 24 hours). - OPTIONAL: a deadline. The player must reach the goal before time runs out, or they lose. See "DEADLINES" below. THE FILE, FIELD BY FIELD ------------------------ { "id": "moonbakery", lowercase letters, digits, - or _ only. Must be unique per game; saves use it. "title": "Moon Bakery", shown as the heading "tagline": "Bake bread for the whole moon.", optional, one line "resources": [ { "id": "flour", lowercase id, used everywhere else "name": "Flour", display name (plural is fine) "cap": 100, optional storage limit; omit = unlimited "start": 0, optional starting amount (default 0) "startsVisible": true, give this to your FIRST resource only; others appear the first time the player has any "desc": "Fine and white." } optional flavor text ], "actions": [ { "id": "sift", "name": "Sift moondust", "gives": { "flour": 1 }, resources added per click "uses": { "sieves": 0.05 }, optional; worn away per click, so 20 clicks use up a sieve. No sieve, no click. The same in every season. A list is a preference order: [{ "brass": 0.01 }, { "sieves": 0.05 }] uses brass while there is any. "unlock": { ... } } optional; omit = visible from the start ], "buildings": [ { "id": "mill", "name": "Crater Mill", "desc": "Grinds moondust into flour.", optional "cost": { "flour": 10 }, price of the FIRST one "costRatio": 1.15, each copy costs this much more (>= 1; 1.07 to 1.4 is typical, default 1.15) "produces": { "flour": 0.3 }, per second, per building (optional) "consumes": { "flour": 1 }, per second, per building (optional) "upkeep": { "water": 0.02 }, per second, per building, in every season, even while "seasonal" rests it (a worker still drinks). Short of it counts as starving (optional) "capBonus": { "flour": 50 }, storage added per building (optional) "unlock": { ... } } ], "crafts": [ { "id": "bake", "name": "Bake a loaf", "cost": { "flour": 20 }, "gives": { "bread": 1 }, "takes": 40, optional; seconds until "gives" arrives (the cost goes at once) "vehicle": "cart", optional, with "takes": a building; each one owned makes one trip at a time (a cart away can't set out) "unlock": { ... } } ], "upgrades": [ { "id": "stones", "name": "Moonstone millstones", "desc": "Mills grind twice as fast.", "cost": { "bread": 5 }, "effect": { "productionMultiplier": { "mill": 2 }, building id -> multiplier "capMultiplier": { "flour": 2 } resource id -> multiplier }, either, both, or no effect at all "unlock": { ... } } ], "goal": { "upgrade": "festival", id of the upgrade that wins the game "message": "The whole moon is fed. You won!" }, "deadline": { ... }, OPTIONAL, see DEADLINES below "calendar": { ... }, OPTIONAL, see SEASONS below "lose": [ ... ] OPTIONAL, see LOSING below } An "unlock" condition can combine any of these. ALL of them must be true: "unlock": { "resources": { "flour": 30 }, have at least this much right now "earned": { "wheat": 15 }, made this much in all, ever; spending it or letting it spoil doesn't undo it "buildings": { "mill": 3 }, own at least this many "upgrades": ["stones"], have bought these upgrades "done": { "gather": 20 }, used that action or craft this many times "season": "autumn", only while it is this season "year": 2 from this year on (looping calendars) } DEADLINES (OPTIONAL) -------------------- Add a "deadline" to make the game a race. The player sees a countdown and loses if time runs out before they buy the goal. Leave it out for a relaxed game with no clock. "deadline": { "seconds": 2000, REAL play time, in seconds (2000 is about 33 minutes). Always seconds: the engine converts it for display. "show": { optional: count down in story units "total": 100, what the full "seconds" is shown as "unit": "years", "label": "You have {left} years remaining" }, {left} and {total} are the ONLY placeholders; the engine fills in the numbers. Don't write numbers yourself. "offline": "frozen", what happens while the player is away: "frozen" - nothing moves (default; best for one-sitting games) "running" - time and production keep going, and they CAN lose while away (for games lasting days) "safe" - both keep going, but stop with 5% of the time left so the ending is always seen "loseMessage": "The sun never rises. The universe notices.", "hint": "Start the seal presses early." shown after a loss } An upgrade can buy more time with "addTime", counted in the displayed units (here: years): "effect": { "addTime": 10 } Only upgrades can add time, never crafts (crafts repeat forever). How long should "seconds" be? GPC's test bot plays your game when it loads and tells you. A fair deadline leaves the bot about 15-35% of the time to spare, because people play slower than the bot. If the bot runs out of time, the report suggests a better "seconds". When you're unsure, write your best guess and adjust it from the report. SEASONS (OPTIONAL) ------------------ A "calendar" gives the game seasons. It plays like the frames of a GIF: each season has its own length, and the calendar loops (counting years) or plays once and stays on its last season. "calendar": { "loop": true, "seasons": [ { "id": "summer", "name": "Summer", "seconds": 240 }, { "id": "winter", "name": "Winter", "seconds": 180 } ] } Then, on items: "seasonal": { "winter": 0 } on an ACTION: what one click gives, times this (0 = frozen). On a BUILDING: how hard it works AND eats (0 = resting). Seasons you don't list count as 1. Only actions and buildings take it: on a craft or upgrade it's an error (use "inSeason" there). "inSeason": ["summer"] only clickable/craftable/buyable in these seasons. Owned buildings keep running; use "seasonal" for that. "seasonalCost": { "winter": { "wood": 2 } } in winter, the wood part of the cost is doubled. Only for things with a cost (buildings, crafts, upgrades); it's an error on actions, whose "uses" is the same every season. On a resource: "decay": 0.01 loses 1% of the stock every second (bread going stale, an oven cooling). From 0 up to, not including, 1. "seasonalDecay": { "winter": 2 } decays twice as fast in winter. "drain": 0.02 loses a fixed 0.02 every second, down to 0 (the household drinking water). "drain": { "summer": 1, "winter": 0 } or a fixed amount by season (snow melting); seasons left out lose 0. "capBonus": { "water": 10 } each whole one held raises water's limit by 10 (jars made by a craft). "cap": 0 holds nothing until a building's capBonus makes room. On a building that consumes something: "leavesAfter": 30 if it can't work at all for 30 seconds in a row, because ANY one thing it consumes has run out (food, wages or work materials alike), one worker leaves. Workers switched off never leave. LOSING (OPTIONAL) ----------------- "lose" ends the game when something stays true too long. "when" is the same as "unlock", plus "below": "lose": [ { "when": { "season": "winter", "below": { "meals": 1 } }, "graceSeconds": 20, "message": "The larder's bare. You join a traveling circus." } ] The condition must hold for "graceSeconds" in a row; the player sees a countdown meanwhile. Keep messages kind: the character survives, the game ends, and the player can try again. The test bot tells you if it loses, and where. A SEASONAL EXAMPLE ------------------ { "id": "orchard", "title": "Winter Orchard", "calendar": { "loop": true, "seasons": [ { "id": "summer", "name": "Summer", "seconds": 120 }, { "id": "winter", "name": "Winter", "seconds": 60 } ] }, "resources": [ { "id": "apples", "name": "Apples", "startsVisible": true, "decay": 0.01 }, { "id": "cider", "name": "Cider" } ], "actions": [ { "id": "pick", "name": "Pick apples", "gives": { "apples": 1 }, "seasonal": { "winter": 0 } } ], "buildings": [ { "id": "tree", "name": "Apple tree", "cost": { "apples": 10 }, "costRatio": 1.2, "produces": { "apples": 0.5 }, "seasonal": { "winter": 0 } } ], "crafts": [ { "id": "press", "name": "Press cider", "cost": { "apples": 5 }, "gives": { "cider": 1 } } ], "upgrades": [ { "id": "fair", "name": "Win the county fair", "cost": { "cider": 30 }, "inSeason": ["summer"] } ], "goal": { "upgrade": "fair", "message": "Best cider in the county!" }, "lose": [ { "when": { "season": "winter", "below": { "cider": 1 } }, "graceSeconds": 15, "message": "No cider to trade for firewood. You spend the winter with your cousins." } ] } END OF SEASONAL EXAMPLE RULES THE ENGINE CHECKS ----------------------- 1. Every id is unique across the whole file (a resource and a building can't share an id). 2. Every resource named anywhere (cost, gives, produces, consumes, capBonus, unlock, capMultiplier) must be listed in "resources". Every building/upgrade named must exist too. 3. Amounts are plain numbers >= 0. Caps are >= 0 or left out. 4. Nothing can cost more of a resource than its cap can ever reach. If something costs 500 flour and flour's cap is 100, some building's capBonus or an upgrade's capMultiplier must be able to raise it. 5. The game needs a first step: at least one action with no unlock (or a starting resource) so the player can begin. 6. "id" and "title" are required. 7. If there's a "deadline": "seconds" > 0, "offline" is frozen, running or safe, and the label uses only {left} and {total}. "addTime" appears only on upgrades, and only in games with a deadline. 8. Seasons named anywhere must be in "calendar", and a game without a calendar can't use "seasonal", "inSeason", "seasonalCost", "seasonalDecay" or a "season" unlock. "year" needs "loop": true. 9. "done" names an action or craft, with a whole number >= 1. 10. "decay" is from 0 up to (not including) 1; "leavesAfter" > 0 only on buildings that consume something; every "lose" has "when" and a "message". DESIGN TIPS THAT MAKE IT FUN ---------------------------- - Start with one action and a first building that costs about 10 clicks. - Introduce something new every minute or two early on, then every few minutes. Each unlock should make the player go "ooh". - Build a chain: raw resource -> processed resource -> rare resource. A building that consumes one resource to produce another is the heart of the game. - Use storage caps to force choices: the player must build storage before they can afford the next big thing. - Upgrades that double something feel great. Put one in every stage. - 4-6 resources, 4-8 buildings, 1-3 crafts and 4-8 upgrades is a good size for a 30-60 minute game. - Name things with personality. Descriptions are where the story lives. A COMPLETE TINY EXAMPLE ----------------------- { "id": "moonbakery", "title": "Moon Bakery", "tagline": "Bake bread for the whole moon.", "resources": [ { "id": "flour", "name": "Flour", "cap": 100, "startsVisible": true }, { "id": "bread", "name": "Bread", "cap": 20 } ], "actions": [ { "id": "sift", "name": "Sift moondust", "gives": { "flour": 1 } } ], "buildings": [ { "id": "mill", "name": "Crater Mill", "cost": { "flour": 10 }, "costRatio": 1.12, "produces": { "flour": 0.3 }, "unlock": { "resources": { "flour": 5 } } }, { "id": "oven", "name": "Low-Gravity Oven", "cost": { "flour": 60 }, "consumes": { "flour": 1 }, "produces": { "bread": 0.1 }, "unlock": { "buildings": { "mill": 4 } } }, { "id": "pantry", "name": "Pantry", "cost": { "flour": 40, "bread": 5 }, "costRatio": 1.3, "capBonus": { "bread": 20, "flour": 50 }, "unlock": { "resources": { "bread": 3 } } } ], "crafts": [], "upgrades": [ { "id": "stones", "name": "Moonstone millstones", "desc": "Mills grind twice as fast.", "cost": { "bread": 10 }, "effect": { "productionMultiplier": { "mill": 2 } }, "unlock": { "resources": { "bread": 5 } } }, { "id": "festival", "name": "Bread Festival", "desc": "Feed everyone. Wins the game.", "cost": { "bread": 60 }, "unlock": { "upgrades": ["stones"] } } ], "goal": { "upgrade": "festival", "message": "The whole moon is fed. You won!" } } PLAYING YOUR GAME ----------------- Open the GPC "Make your own" page, then upload the .json file or paste its text. If anything breaks a rule, the page lists exactly what to fix: paste that list back to your AI and ask for a corrected file. When the game loads, you get a share link so friends can play it too.