Make a Deckbuilding Battle: Energy, Block and Discard Piles
Build Paper Duel: a visible enemy intent, two card types and a small turn-based combat loop.

Thumbnail: an actual matching workshop game. It is a gameplay reference, not evidence that a save, inventory, network or native reverse-engineering integration has been demonstrated.
Difficulty: beginner to intermediate. Prerequisites: basic variables, functions and a test copy of your project. Reference: Forge workshop 1.0, browser ES modules and Node 24 checks. Engine-specific translation is a separate integration.
What you will build
Win one encounter using Strike, Guard, energy and visible intent.
Play Paper Duel →Download complete MIT workshop- Extract into a new folder and run
node check.mjsfrom that folder. - For the browser games, run
python3 -m http.server 8080with Python 3 and openhttp://localhost:8080/index.html. Do not open modules with file://. - Read the full setup instructions and the original code licence. Keep your existing game on a separate test branch.
The JavaScript behaviour checks and native C comparison can run independently of the browser. Ghidra UI, physical-phone and your engine integration are separate checks. This is a small reference, not a certification of your project.
Explore the related game idea · Start with Build a Game · Improve your existing game
Five practical steps
Make one deterministic encounter
Start Deck battler. The player has eighteen health and three energy; the enemy has eighteen health and announces seven damage. Strike deals six; Guard adds five block. These small numbers let you calculate a turn before playing it.
Expected result: A visible hand, energy count and enemy intent.
Check it: Confirm the initial hand is Strike, Guard, Strike and every card costs one energy.
playObserve the inputs → check the state → compare the resultOwn card play in one function
deck.play validates a current hand index, energy and active encounter before removing the card. Apply its effect, spend energy and put it in discard. Render from the resulting hand so removed-card indices do not refer to yesterday’s UI.
Expected result: A card leaves the hand exactly once and spends one energy.
Check it: Click an invalid index or play with zero energy; health, hand and piles stay unchanged.
Resolve the enemy turn explicitly
End turn applies max(0,7-block) damage, clears block, discards the unused hand and refills energy. Draw up to three cards, refilling the draw pile from discard when empty. This reference uses a fixed order to support repeatable tests; it is not a random shuffle.
Expected result: No negative damage, persistent old block or unlimited hand.
Check it: Play Guard, then end turn: take two damage and start the next turn with zero block.
Stop combat immediately at an outcome
A lethal Strike ends combat before the enemy can retaliate. A lethal enemy turn also ends the encounter. Every later play/end-turn action rejects the finished state. Restart creates new piles instead of reusing an old hand.
Expected result: A win or loss that cannot keep mutating in the background.
Check it: Win with three total strikes; repeatedly press End turn and confirm health and piles remain unchanged.
Extend toward a deckbuilder
This is a battle recipe, not a complete roguelike. Add one post-win card reward and a second encounter before a map, shop or hundreds of cards. If you add shuffle, inject a seeded random source and preserve the deterministic test path.
Expected result: A small original two-battle run with bounded card rules.
Check it: Test empty piles, duplicate cards, restart, touch controls and save schema before adding persistent runs.
Read and reuse the actual code
deck.mjs: complete source · Standalone behavioural checks · Shared browser runner and input. Original BINX Forge code, MIT; the package includes every required file and its notice.
Inspect complete deck.mjs
export function create(){return {hp:18,enemy:18,energy:3,block:0,turn:1,hand:['strike','guard','strike'],discard:[],draw:['guard','strike','guard'],ended:false,won:false};}
const refill=s=>{while(s.hand.length<3){if(!s.draw.length)s.draw=s.discard.splice(0);if(!s.draw.length)break;s.hand.push(s.draw.shift());}};
export function play(s,index){if(s.ended||s.energy<1||!Number.isInteger(index)||index<0||index>=s.hand.length)return false;const c=s.hand.splice(index,1)[0];s.energy--;if(c==='strike')s.enemy=Math.max(0,s.enemy-6);else s.block+=5;s.discard.push(c);if(!s.enemy){s.ended=true;s.won=true;}return true;}
export function endTurn(s){if(s.ended)return false;s.hp=Math.max(0,s.hp-Math.max(0,7-s.block));s.block=0;s.discard.push(...s.hand.splice(0));s.energy=3;s.turn++;refill(s);if(!s.hp){s.ended=true;s.won=false;}return true;}
Code rights: the included MIT notice permits use, modification and distribution, including commercial games and source products, with the copyright and licence notice. Added third-party files have their own terms. Read the official licence & usage terms.
Common failures and fixes
The player takes negative damage
Clamp incoming damage after block; block does not heal.
A dead enemy attacks
Check terminal outcomes immediately after each accepted card effect.
Random tests are flaky
Keep a seeded shuffle or deterministic reference so a failure can be replayed.
Make Your Game Better
Change one system after the baseline works. Keep the free reference and compare the same inputs before and after.
Add one new card
Write its cost, target and effect as data; test energy and outcome boundaries first.
Add a reward screen
Offer a bounded choice after victory, then construct the next battle from the selected deck.
Optional building blocks from original creators

Godot Engine contributors · Original screenshot ↗ · CC BY 4.0 ↗. Resized and compressed.
Godot Engine contributorsGodot
Free, open-source game editor for 2D and 3D projects, with scene, animation and interface tools.

UI Pack
Interface artwork for buttons, panels and sliders.
Inspect exact formats and editions on each resource page. Pay for a resource only when it fills an identified gap; the free code exercise needs no paid engine or pack.
Licensing summary, not legal advice. Before publishing or selling, check exact terms for finished-game use, reselling files and including files in a source/template product separately.
Learn at the original sources
Sources checked 11 October 2026. The numbered plan is original Forge instruction; linked documentation does not imply every engine or device has been tested.
Take this guide to your AI
Review and copy into your assistant. Nothing is sent automatically. These prompts include the complete focus source, full-package links, checks and compatibility limits.
Review a prompt or select its text manually.