Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Build a card game: card data, deck/hand/discard zones, draw/shuffle/reshuffle, a turn structure, costs, and effect resolution. Use for a deckbuilder, TCG/CCG, or roguelike deckbuilder.
.claude/skills/gamedev-skills-card-game/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-08 | ✗→✓ | ▲ Improved | 67% | 0% |
| case-01 | ✓→✓ | = Same ✓ | 17% | 0% |
| case-02 | ✓→✓ | = Same ✓ | 60% | 0% |
| case-03 | ✓→✓ | = Same ✓ | 97% | 0% |
| case-04 | ✓→✓ | = Same ✓ | 39% | 0% |
A playbook for card games — card data, the deck/hand/discard zones, the turn structure, and how card effects resolve. This is a compositional skill: it models cards as data and wires them to UI. It does not re-teach data assets or UI nodes; it defines the zone model, the draw machinery, and the effect-resolution rules that keep a card game correct and bug-free.
(deck → hand → play → discard): deckbuilder, TCG/CCG, solitaire, roguelike deckbuilder.
When not to use: board/tile state with matching rules → puzzle. RPG with an incidental card battler → start from rpg. For defining cards as assets, use godot-resources / unity-scriptableobjects; for the hand/drag UI, use godot-ui-control.
Draw to your hand → spend resources to play cards → effects resolve and change the board → end the turn (cleanup/discard) → opponent/next phase → repeat until a win condition. Depth comes from the combinations a hand allows; the engine's job is to resolve them unambiguously.
| Knob | Effect | Notes | |------|--------|-------| | Starting hand / draw-per-turn | tempo, consistency | More draw = less variance. | | Hand size limit | hoarding vs. use | Discard down at end of turn. | | Deck size (min) | consistency | Smaller = more reliable combos. | | Resource curve | what's playable when | "Mana curve" paces power. | | Card rarity / power budget | balance | Stronger cards cost more / are rarer. | | Determinism vs. randomness | skill vs. swing | Shuffle + random effects add variance. | | Reshuffle rules | deck-out, fatigue | Reshuffle discard, or punish empty deck. | | Removal / answers | counterplay | Every threat needs an answer in the pool. |
python# Pseudocode. A card is in exactly one zone at a time; moving = remove here, add there. def draw(n): for _ in range(n): if not deck: if not discard: # truly empty: deck-out (lose, or take fatigue) on_deck_out(); return deck.extend(discard) # reshuffle discard into deck discard.clear() shuffle(deck, rng) # use a seeded RNG (see save-systems for replays) hand.append(deck.pop())
python# Pseudocode. Effects are a data list interpreted by the engine — not bespoke code per card. card = { "id": "fireball", "cost": 3, "type": "spell", "effects": [ {"op": "damage", "amount": 6, "target": "chosen_enemy"} ], } def play(card, caster): if resources[caster] < card.cost: return False # can't afford resources[caster] -= card.cost move(card, from_zone=hand, to_zone=play_or_discard(card)) for fx in card.effects: resolve_effect(fx, caster) # one interpreter handles every card return True
python# Pseudocode. Fixed phases keep timing windows (triggers, priority) unambiguous. PHASES = ["untap", "draw", "main", "combat", "end"] def take_turn(player): for phase in PHASES: enter_phase(player, phase) # fire "on_phase" triggers here if phase == "draw": draw(1) if phase == "main": await player_plays_cards() if phase == "combat": resolve_combat() if phase == "end": discard_to_hand_limit(player); clear_temporary_effects()
move = remove-then-add, and assert no card appears twice.
or define deck-out/fatigue explicitly (Pattern 1).
by a small set of operations (Pattern 2).
defined order (a queue or stack); document LIFO vs. FIFO (refs).
ensure removal exists for every threat archetype.
atomic: validate cost + targets first, then commit.
godot-resources / unity-scriptableobjects — define each card as a data asset.game-ui-ux for layout, scaling, and focus navigation; godot-ui-control for hand layout, drag/drop, zone counts, and targeting prompts.save-systems for collection, run state (roguelike deckbuilder), and seeded replays.game-ai for an AI that evaluates playable cards and picks targets.audio-design for cues.godot-gdscript / unity-csharp-scripting for the effect interpreter.archetypes, and shuffle fairness, read references/effect-resolution.md.
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | pass→pass | 23,516 | 19,156 | -19% | 1 | 1 | 0% | 4,946 | 5,808 | +17% | 0 | 0 | — |
case-02 | pass→pass | 20,126 | 20,085 | -0% | 1 | 1 | 0% | 3,584 | 5,739 | +60% | 0 | 0 | — |
case-03 | pass→pass | 10,474 | 9,540 | -9% | 1 | 1 | 0% | 1,766 | 3,472 | +97% | 0 | 0 | — |
case-04 | pass→pass | 14,321 | 10,826 | -24% | 1 | 1 | 0% | 2,584 | 3,579 | +39% | 0 | 0 | — |
case-05 | pass→pass | 3,136 | 2,763 | -12% | 1 | 1 | 0% | 520 | 2,183 | +320% | 0 | 0 | — |
case-22 | pass→pass | 15,189 | 15,622 | +3% | 1 | 1 | 0% | 2,568 | 4,172 | +62% | 0 | 0 | — |
case-06 | pass→pass | 13,107 | 9,760 | -26% | 1 | 1 | 0% | 2,293 | 3,447 | +50% | 0 | 0 | — |
case-07 | pass→pass | 11,764 | 7,382 | -37% | 1 | 1 | 0% | 2,194 | 2,984 | +36% | 0 | 0 | — |
case-08 | fail→pass | 12,578 | 12,049 | -4% | 1 | 1 | 0% | 2,313 | 3,865 | +67% | 0 | 0 | — |
case-09 | pass→pass | 14,756 | 10,442 | -29% | 1 | 1 | 0% | 2,162 | 3,277 | +52% | 0 | 0 | — |
case-10 | pass→pass | 17,026 | 9,796 | -42% | 1 | 1 | 0% | 2,963 | 3,411 | +15% | 0 | 0 | — |
case-11 | pass→pass | 10,000 | 8,136 | -19% | 1 | 1 | 0% | 1,619 | 3,039 | +88% | 0 | 0 | — |
case-12 | pass→pass | 7,740 | 7,401 | -4% | 1 | 1 | 0% | 1,356 | 2,873 | +112% | 0 | 0 | — |
case-13 | pass→pass | 12,116 | 10,011 | -17% | 1 | 1 | 0% | 2,071 | 3,430 | +66% | 0 | 0 | — |
case-14 | pass→pass | 11,151 | 8,199 | -26% | 1 | 1 | 0% | 1,762 | 3,208 | +82% | 0 | 0 | — |
case-15 | pass→pass | 7,651 | 3,961 | -48% | 1 | 1 | 0% | 1,258 | 2,285 | +82% | 0 | 0 | — |
case-16 | pass→pass | 7,336 | 4,877 | -34% | 1 | 1 | 0% | 1,216 | 2,418 | +99% | 0 | 0 | — |
case-17 | pass→pass | 11,032 | 9,853 | -11% | 1 | 1 | 0% | 1,672 | 3,275 | +96% | 0 | 0 | — |
case-18 | pass→pass | 7,766 | 3,224 | -58% | 1 | 1 | 0% | 1,325 | 2,295 | +73% | 0 | 0 | — |
case-19 | pass→pass | 13,062 | 11,126 | -15% | 1 | 1 | 0% | 2,381 | 3,595 | +51% | 0 | 0 | — |
case-20 | pass→pass | 20,577 | 22,397 | +9% | 1 | 1 | 0% | 4,477 | 6,308 | +41% | 0 | 0 | — |
case-21 | pass→pass | 9,859 | 7,901 | -20% | 1 | 1 | 0% | 1,633 | 2,862 | +75% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +5 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.