Javascript library for card games (fork of the abandoned card.js).
To create a new deck, you can use the Deck() method provided by cards.js. Here's how to initialize a deck and add all the cards to it:
let cards = new CardsJS();
let deck = cards.Deck();
deck.addCards(cards.all);
A hand in this library is essentially a deck with a label and position defined. Here's how to create a hand and deal cards to it:
let yours = cards.Deck({
type: 'hand', // Type: 'hand' indicates it will be rendered as a hand
label: 'Your Hand', // Label for the hand
y: cards.playableArea.bottom // Position at the bottom of the playable area
});
deck.deal(3, [yours]); // Deal 3 cards to 'Your Hand'
By default, cards are faced down. To reveal the cards, you can set faceUp to true:
yours.faceUp = true; // Make cards face-up
deck.deal(7, [yours]); // Deal 7 more cards
To create a second hand and deal cards to it, you can follow this example:
let theirs = cards.Deck({
type: 'hand',
label: 'Other Hand',
y: cards.playableArea.top // Position at the top of the playable area
});
deck.deal(5, [theirs]); // Deal 5 cards to 'Other Hand'
You can bind events to hands and cards. For example, show the name of the card when hovering over it:
yours.on('mouseenter',
card => yours.label.text = `This is ${card}`);
theirs.on('mouseenter',
card => theirs.label.text = 'Other Hand');
deck.on('mouseenter',
card => deck.label.text = 'Main Deck');
Now to hide the labels when not hovering:
theirs.on('mouseleave',
card => theirs.label.text = '')
deck.on('mouseleave',
card => deck.label.text = '')
yours.on('mouseleave',
card => yours.label.text = '')
deck.label.sticky = 'bottom'
To trigger the events programatically:
theirs.trigger('mouseleave')
deck.trigger('mouseleave')
yours.trigger('mouseleave')
yours
.deal(-1, [ deck ])
.then(_ => theirs.deal(-1, [ deck ]) )
.then(_ => deck.shuffle() )
.then(_ => deck.deal(5, [ yours, theirs ]) )
You can sort a hand by suit, rank, or both:
yours.shuffle().sort() // by default: suit
Here is your hand sorted by rank:
yours.shuffle().sort('rank')
Here is your hand sorted by rank, then suit:
yours.shuffle().sort('rank-then-suit')
Here is your hand sorted by suit, then rank:
yours.shuffle().sort('suit-then-rank')
Now let's define some rules and create a game:
// Define a function to check if a card can be played
let canPlay = (card, top) => {
return card.suitIndex === top?.suitIndex ||
card.rankIndex === top?.rankIndex;
};
You can set up a discard pile where cards are placed after they are played:
deck.x -= 50;
deck.render();
let pile = cards.Deck({
label: 'discard',
sticky: 'top',
faceUp: true
});
pile.x += 50;
pile.addCard(deck.topCard());
pile.render();
let canDiscard = card => canPlay(card, pile.topCard())
Here’s how to bind click events to allow players to interact with the deck and hand:
// Handle mouse enter event to show playable cards
yours.on('mouseenter', card => {
canDiscard(card)
? yours.label.text = `You can play ${card}`
: yours.label.text = `This is ${card}`;
});
// Handle deck click to draw cards
let gameOver = false;
deck.click(card => {
if (gameOver) return;
const ableToPlay = yours.filter(canDiscard).pop();
if (!ableToPlay && card === deck.topCard()) {
deck.deal(1, [yours]);
return;
}
deck.label.text = 'Able to play \n No more draws!';
});
Check for win or loss conditions when clicking cards:
yours.click((card) => {
const playable = yours.filter(canDiscard)
if (playable.includes(card)) {
pile.addCard(card)
yours.label.text = `Played ${card}.`
const gameWon = yours.length === 0
const gameLost = !playable && deck.length === 0
if (gameWon) alert('You Won!')
if (gameLost) alert('You Lost!')
gameOver = gameWon || gameLost
return
}
yours.label.text = `Can't play ${card}!`
})
Click on discard pile to end the game.
this.disableNext() // meta code
pile.click( _ => {
if (!gameOver) return
yours
.deal(-1, [ deck ])
.then(_ => theirs.deal(-1, [ deck ]) )
.then(_ => pile.deal(-1, [ deck ]) )
.then(_ => deck.x += 50 )
.then(_ => this.enableNext() ) // meta code
})
Set up a table with multiple players arranged in a circular layout:
const r = 150; // radius of the layout
const center = cards.getCenter()
let names = ['You', 'Alice', 'Bob', 'Charlie'];
let position = ['left', 'top', 'right', 'bottom'];
let perspective = ['east', 'south', 'west', 'north'];
let layout = CardsJS.roundLayout(names, {
...center, radius: r
});
// Arrange players in the layout
let players = layout.map(
(pos, i) => cards.Deck({
...pos,
faceUp: i === 0,
label: names[i],
sticky: position[i],
seenFrom: perspective[i]
})
);
// Deal cards to all players
deck.deal(-1, players)