Three table manners: Safari replays, docked creature cards, a quiet hand
Safari collapsed the replay board to nothing: an svg with only a viewBox has no intrinsic size there, and inside the replay's max-height flex column WebKit sized it 0x0 while Chrome inferred the ratio and filled the frame. Explicit width/height attributes (doubled, so the CSS max-* caps still govern the display size) give every engine the same answer — verified 560x560 in both WebKit and Chromium, with the main board-zone rendering unchanged. Commanding your own creature no longer opens the centered card peek — a modal squarely blocks the squares you are about to march it across. The card now docks in the paper rail with its live stats, the one place a card enlarges outside the center of the table. Enemy creatures and idle peeks keep the modal; they ask nothing of the board. And once an object is pocketed, the hand goes visibly quiet: cards dim and refuse selection instead of walking you through target-picking toward an engine refusal, with a rail slip saying what remains (draw and end the turn). Counters, chaos shields, and discards still play — an ambush sprung by the very pickup must be answerable. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
7bd82d7679
commit
1275ac9287
+44
-11
@@ -108,6 +108,17 @@
|
|||||||
);
|
);
|
||||||
const youMustDiscard = $derived(view != null && view.pendingDiscard === view.you);
|
const youMustDiscard = $derived(view != null && view.pendingDiscard === view.you);
|
||||||
const youMustShield = $derived(view?.chaosPending?.queue[0] === view?.you && view != null);
|
const youMustShield = $derived(view?.chaosPending?.queue[0] === view?.you && view != null);
|
||||||
|
/** Picking up an object ends the turn's actions: the hand goes quiet until
|
||||||
|
* the draw — but never while a counter, shield, or discard is owed. */
|
||||||
|
const actionsSpent = $derived(
|
||||||
|
view != null && isYourTurn && view.turn.actionsEnded &&
|
||||||
|
!youMustRespond && !youMustShield && !youMustDiscard,
|
||||||
|
);
|
||||||
|
const commandedCreature = $derived(
|
||||||
|
selectedCreature && view
|
||||||
|
? (view.creatures.find((c) => c.id === selectedCreature) ?? null)
|
||||||
|
: null,
|
||||||
|
);
|
||||||
const holdingWard = $derived(view?.yourHand.some((c) => c.cardId === "ward") ?? false);
|
const holdingWard = $derived(view?.yourHand.some((c) => c.cardId === "ward") ?? false);
|
||||||
/** A live moment to interrupt: another wizard acts, no attack is pending. */
|
/** A live moment to interrupt: another wizard acts, no attack is pending. */
|
||||||
const canInterruptNow = $derived(
|
const canInterruptNow = $derived(
|
||||||
@@ -228,6 +239,7 @@
|
|||||||
discardSelection = next;
|
discardSelection = next;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (actionsSpent) return; // picking up an object ended the turn's actions
|
||||||
if (!isYourTurn) {
|
if (!isYourTurn) {
|
||||||
// Live interruption: Interrupt / Opportunity Fire may be played during
|
// Live interruption: Interrupt / Opportunity Fire may be played during
|
||||||
// another player's turn (when no attack is pending).
|
// another player's turn (when no attack is pending).
|
||||||
@@ -571,15 +583,10 @@
|
|||||||
}
|
}
|
||||||
const mine = creature.controllerId === view.you || creature.kind === "democratic-monster";
|
const mine = creature.controllerId === view.you || creature.kind === "democratic-monster";
|
||||||
if (mine) {
|
if (mine) {
|
||||||
const selecting = selectedCreature !== creatureId;
|
// Commanding your own creature docks its card in the rail instead of
|
||||||
selectedCreature = selecting ? creatureId : null;
|
// opening the centered peek — a modal would block the very board
|
||||||
if (selecting) {
|
// squares you are about to march it across.
|
||||||
peekCard = { instanceId: `peek-${creature.kind}`, cardId: creature.kind };
|
selectedCreature = selectedCreature !== creatureId ? creatureId : null;
|
||||||
peekCreatureId = creature.id;
|
|
||||||
} else {
|
|
||||||
peekCard = null;
|
|
||||||
peekCreatureId = null;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
peekAt(creature.position);
|
peekAt(creature.position);
|
||||||
}
|
}
|
||||||
@@ -1153,6 +1160,18 @@
|
|||||||
Tap its token to command it.
|
Tap its token to command it.
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
|
{#if commandedCreature}
|
||||||
|
<div class="creature-dock">
|
||||||
|
<Card
|
||||||
|
card={{ instanceId: `dock-${commandedCreature.kind}`, cardId: commandedCreature.kind }}
|
||||||
|
onfaq={(id) => (faqCardId = id)}
|
||||||
|
/>
|
||||||
|
<div class="peek-note">{creatureStats(commandedCreature)}</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{#if actionsSpent}
|
||||||
|
<div class="slip">Your spellwork is spent for this turn — all that remains is to draw and end it.</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
{#if view.yourAmbushes.length > 0}
|
{#if view.yourAmbushes.length > 0}
|
||||||
{#each view.yourAmbushes as a (a.id)}
|
{#each view.yourAmbushes as a (a.id)}
|
||||||
@@ -1258,7 +1277,7 @@
|
|||||||
{#if sc}
|
{#if sc}
|
||||||
<span>Commanding <strong>{cardDef(sc.kind).name}</strong> — {creatureStats(sc)}.
|
<span>Commanding <strong>{cardDef(sc.kind).name}</strong> — {creatureStats(sc)}.
|
||||||
Tap a square beside it to march, a target in its square to attack.</span>
|
Tap a square beside it to march, a target in its square to attack.</span>
|
||||||
<button class="hint-cancel" onclick={() => { selectedCreature = null; peekCard = null; peekCreatureId = null; }}>done</button>
|
<button class="hint-cancel" onclick={() => (selectedCreature = null)}>done</button>
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
{#if youMustRespond && view.stack}
|
{#if youMustRespond && view.stack}
|
||||||
@@ -1427,7 +1446,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div class="hand" aria-label="your hand">
|
<div class="hand" class:spent={actionsSpent && !discardMode && discardSelection.size === 0} aria-label="your hand">
|
||||||
{#each view.phase === "finished" ? [] : view.yourHand as card (card.instanceId)}
|
{#each view.phase === "finished" ? [] : view.yourHand as card (card.instanceId)}
|
||||||
<Card
|
<Card
|
||||||
{card}
|
{card}
|
||||||
@@ -2018,6 +2037,20 @@
|
|||||||
.big-peek :global(.card:hover) { transform: scale(2.1); }
|
.big-peek :global(.card:hover) { transform: scale(2.1); }
|
||||||
.big-peek { display: flex; flex-direction: column; align-items: center; }
|
.big-peek { display: flex; flex-direction: column; align-items: center; }
|
||||||
.big-peek-note { margin-top: 6.8rem; max-width: 15rem; font-size: 0.8rem; }
|
.big-peek-note { margin-top: 6.8rem; max-width: 15rem; font-size: 0.8rem; }
|
||||||
|
.creature-dock {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.3rem;
|
||||||
|
}
|
||||||
|
.creature-dock :global(.card) { cursor: default; }
|
||||||
|
.creature-dock :global(.card:hover) { transform: none; }
|
||||||
|
.hand.spent :global(.card) {
|
||||||
|
opacity: 0.45;
|
||||||
|
filter: grayscale(0.5);
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
.hand.spent :global(.card:hover) { transform: none; }
|
||||||
.tier-pick {
|
.tier-pick {
|
||||||
background: #f6f0df;
|
background: #f6f0df;
|
||||||
border: 1px solid #b3a687;
|
border: 1px solid #b3a687;
|
||||||
|
|||||||
@@ -149,8 +149,13 @@
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<!-- Explicit width/height give the svg an intrinsic size: Safari cannot
|
||||||
|
derive one from the viewBox alone and collapses the board to 0x0 inside
|
||||||
|
a max-height flex column. Doubled so CSS max-* caps still govern. -->
|
||||||
<svg
|
<svg
|
||||||
viewBox={`-8 -8 ${view.board.width * CELL + 16} ${view.board.height * CELL + 16}`}
|
viewBox={`-8 -8 ${view.board.width * CELL + 16} ${view.board.height * CELL + 16}`}
|
||||||
|
width={(view.board.width * CELL + 16) * 2}
|
||||||
|
height={(view.board.height * CELL + 16) * 2}
|
||||||
class="board"
|
class="board"
|
||||||
>
|
>
|
||||||
<!-- floor -->
|
<!-- floor -->
|
||||||
|
|||||||
Reference in New Issue
Block a user