miaoda-game-canasta-react
v0.3.3
Published
React DOM bindings for the fixed four-player Classic Canasta rules profile.
Readme
miaoda-game-canasta-react
React bindings and a framework-neutral controller for the fixed four-player Classic Canasta profile.
pnpm add miaoda-game-canasta-reactimport {
createCanastaGame,
CanastaController,
useCanastaView,
} from 'miaoda-game-canasta-react';
const controller = new CanastaController(
createCanastaGame({ playerIds: ['a', 'b', 'c', 'd'], seed: 2026 }),
'a',
);
function TurnControls() {
const view = useCanastaView(controller);
return view.legalActions.canDrawStock ? (
<button
onClick={() => controller.dispatch({
type: 'draw-stock',
playerId: view.viewerId,
})}
>
Draw
</button>
) : null;
}Render controls only from the current legalActions. Use meldResources,
discardPickupNaturalCardIds, blackThreeMeldCardIds, and discardCardIds as exact action inputs;
the controller does not choose a meld strategy. useCanastaController owns a controller for one
mounted component lifetime, while useCanastaView subscribes to any existing controller.
The React view contains the selected player's hand and all face-up table facts. Opponent hands and stock order stay outside React. A stock draw appears only in the acting viewer's next view. A whole discard-pile pickup reveals the cards committed to melds while cards retained in hand remain private.
Commits and reconnects
const unsubscribe = controller.onCommit(({ revision, view, events }) => {
queueAnimations(events);
persistRevision(revision);
renderHud(view);
});
controller.replaceSnapshot(JSON.parse(savedJson), serverRevision);
controller.setViewerId('b');Only accepted actions advance revision or publish commits. Commit events are detached and ordered:
draw events never contain card ids, while meld and discard events carry only public cards. Rejected
actions, invalid viewers, inconsistent snapshots, and lower revisions do not partially change the
controller. Viewer changes publish a new safe view without advancing the game revision.
Phaser
pnpm add miaoda-game-command-phaserimport { PhaserGameBridge } from 'miaoda-game-command-phaser';
const bridge = new PhaserGameBridge().setup(controller);
bridge.consumeWith((event) => animateCanastaEvent(event));
bridge.dispatch({ type: 'draw-stock', playerId: bridge.view.viewerId });
bridge.destroy();
unsubscribe();The bridge exposes the same player-safe view as React and consumes projected events in commit FIFO order. Animate a private stock draw from the view transition, not from an event card id. Animate melds, discards, settlement, and new-hand transitions from their public events and resulting view.
