Shared types
The prompt protocol is built from a small set of reusable structures. Instead of redefining them on every prompt page, they’re collected here — each prompt’s arguments link back to the entries it uses.
Every block below is generated from the same source as the engine bindings
(ts-rs for TypeScript, the manabrew-protocol crate for Rust), so it can’t
drift from what’s actually on the wire.
PromptPresentation
Section titled “PromptPresentation”The title/description header most modal prompts open with.
interface PromptPresentation { title: string; description?: string; text?: string; sourceCardId?: string; targets: Array<TargetRef>;}#[serde(rename_all = "camelCase")]pub struct PromptPresentation { pub title: String, #[serde(default, skip_serializing_if = "Option::is_none")] pub description: Option<String>, #[serde(default, skip_serializing_if = "Option::is_none")] pub text: Option<String>, #[serde(default, skip_serializing_if = "Option::is_none")] pub source_card_id: Option<String>, #[serde(default)] pub targets: Vec<TargetRef>,}
References: TargetRef
TargetRef
Section titled “TargetRef”A typed reference to a player, card, or spell. The kind tag tells the client
which id space id belongs to.
type TargetRef = | { kind: "player"; id: string } | { kind: "card"; id: string } | { kind: "spell"; id: string };#[serde( tag = "kind", rename_all = "camelCase", rename_all_fields = "camelCase")]pub enum TargetRef { Player { id: String }, Card { id: String }, Spell { id: String },}ScryDestination
Section titled “ScryDestination”The zones a scry-style prompt can sort cards into.
type ScryDestination = | "libraryTop" | "libraryBottom" | "graveyard" | "exile" | "hand";#[serde(rename_all = "camelCase")]pub enum ScryDestination { LibraryTop, LibraryBottom, Graveyard, Exile, Hand,}DiceRollEntry
Section titled “DiceRollEntry”One player’s dice result.
interface DiceRollEntry { label?: string; playerId?: string; naturalResults: Array<number>; finalResults: Array<number>; ignoredRolls: Array<number>; highlighted: boolean;}#[serde(rename_all = "camelCase")]pub struct DiceRollEntry { #[serde(default, skip_serializing_if = "Option::is_none")] pub label: Option<String>, #[serde(default, skip_serializing_if = "Option::is_none")] pub player_id: Option<String>, pub natural_results: Vec<i32>, pub final_results: Vec<i32>, pub ignored_rolls: Vec<i32>, #[serde(default)] pub highlighted: bool,}AvailableAction
Section titled “AvailableAction”One legal action offered by chooseAction: cast a spell, activate an ability, or undo a mana activation.
type AvailableAction = { id: string } & ( | { type: "cast"; cardId: string; mode: string; modeLabel: string } | ({ type: "activateAbility" } & ActivatableAbilityInfo) | { type: "undoMana"; cardId: string } | { type: "delve"; cardId: string } | { type: "undelve"; cardId: string });pub struct AvailableAction { pub id: String, #[serde(flatten)] pub kind: AvailableActionKind,}
References: ActivatableAbilityInfo
ActivatableAbilityInfo
Section titled “ActivatableAbilityInfo”A mana ability the player can activate while paying a cost (payManaCost).
interface ActivatableAbilityInfo { cardId: string; abilityIndex: number; description: string; isManaAbility: boolean; cost?: string; producedMana?: Array<Mana>;}#[serde(rename_all = "camelCase")]pub struct ActivatableAbilityInfo { pub card_id: String, pub ability_index: usize, pub description: String, pub is_mana_ability: bool, #[serde(default, skip_serializing_if = "Option::is_none")] pub cost: Option<String>, #[serde(default, skip_serializing_if = "Option::is_none")] pub produced_mana: Option<Vec<Mana>>,}
References: Mana
AttackerOptionDto
Section titled “AttackerOptionDto”A creature that can attack, with the set of targets it may attack (chooseAttackers).
interface AttackerOptionDto { attackerId: string; validTargetIds: Array<string>;}#[serde(rename_all = "camelCase")]pub struct AttackerOptionDto { pub attacker_id: String, pub valid_target_ids: Vec<String>,}AttackTargetDto
Section titled “AttackTargetDto”Something an attacker can be declared against — a player, planeswalker, or battle.
interface AttackTargetDto { id: string; label: string; kind: AttackTargetKind;}#[serde(rename_all = "camelCase")]pub struct AttackTargetDto { pub id: String, pub label: String, pub kind: AttackTargetKind,}
References: AttackTargetKind
AttackTargetKind
Section titled “AttackTargetKind”Which kind of thing an AttackTargetDto is.
type AttackTargetKind = "player" | "planeswalker" | "battle";#[serde(rename_all = "camelCase")]pub enum AttackTargetKind { Player, Planeswalker, Battle,}BlockableAttackerDto
Section titled “BlockableAttackerDto”An incoming attacker and how it may be blocked (chooseBlockers).
interface BlockableAttackerDto { attackerId: string; validBlockerIds: Array<string>; minBlockers: number; maxBlockers?: number; mustBeBlocked: boolean;}#[serde(rename_all = "camelCase")]pub struct BlockableAttackerDto { pub attacker_id: String, pub valid_blocker_ids: Vec<String>, pub min_blockers: u32, #[serde(default, skip_serializing_if = "Option::is_none")] pub max_blockers: Option<u32>, pub must_be_blocked: bool,}