77 Commits
Author SHA1 Message Date
Greyson Parrelli 84900415b2 Fix false draw case. 2026-08-10 16:24:32 -04:00
Greyson Parrelli 6ae4d41976 Put the bug report behind an always-available button.
The debug report was only reachable in DEBUG mode, which is the one mode
a player hitting a real bug won't be running. Move it to a "🐛 Report a
bug" item in the game menu: a note field, a download, and a copy-as-text,
on any server.

That knowingly shows the reporter their opponents' hands and the shop
deck order. Credentials are still required, so a report only ever reaches
someone seated at that table. The buy-any-card panel stays DEBUG-only —
it changes the game; a report only reads it.
2026-08-10 13:42:31 -04:00
Greyson Parrelli 8ccde03023 Add replayable debug reports.
A report dumps everything needed to understand a game that went wrong:
the full state (decks card by card, shop row and tier deck order,
discards, pending choices, banked Mana/Trumpets/apples), the round's
battles, and the whole event log. Available as JSON, which replays, or
text, which reads — and the text ends with a paste-ready repro test.

Battles now record the randomness they consume alongside what they
started from, so a result can be replayed long after the round cleared
those banks: same lineups, same dice, same events, down to the log text.
Results predating the recording say so rather than quietly re-rolling.

Three ways in: the 🐛 panel's download/copy buttons, GET
/api/debug/report (DEBUG-only, since a report holds both players' hands
and the shop deck order), and `mise run report`, which reads the
database directly so a live game can be dumped without DEBUG.
2026-08-10 10:06:06 -04:00
Greyson Parrelli a4f5f6910d Add support for up to 6 players. 2026-07-28 07:36:09 -04:00
Greyson Parrelli e542118175 Stop the hover magnifier sticking open after a drag.
`noMagnify` only suppressed rendering — each card went on tracking hover
underneath it. During a drag the cursor outruns the lifted card (its
transform lands a frame later), so the rows it passes take mouseenter,
and React re-inserts those rows as the list reorders, so the matching
mouseleave often never arrives. Every card left holding stale hover then
popped its preview the moment the drag state cleared, at stale
coordinates, and stayed there until that exact card was hovered and left
again.

noMagnify now means the magnifier is off, not hidden: the handlers come
off and any tracked hover is dropped. Nothing can be left half-armed
regardless of which boundary events the browser does or doesn't deliver.

The drag also cleared its state 180ms after release — its own glide — while
the neighbours it passed keep gliding for anim.ts's MOVE_MS of 240ms. A
row sliding out from under a stationary cursor in that 60ms tail could
re-arm the same stale hover, so the settle window now covers the whole
tray coming to rest.
2026-07-27 16:39:46 -04:00
Greyson Parrelli 8383f0f718 Drag arrange cards by the card, not a grip handle.
Reordering the battle line meant finding a small ⠿ handle beside each
card. Now the card itself is the drag surface, with the gesture split by
input type so it can't collide with the two things a press already means:

  * A mouse lifts the card once the cursor travels 5px. Shorter presses
    stay clicks.
  * A finger has to hold still for 220ms first. Arrange is the one screen
    tall enough to scroll, and a finger swiping a card almost always
    means scrolling — so the card deliberately does NOT set
    `touch-action: none`. The hold is what distinguishes a drag, and once
    it lands the scroll is cancelled by preventing `touchmove`, which
    works precisely because a still finger hasn't started one.

That also fixes the phone's tap-to-magnify fighting the drag: only a
press that never became a drag counts as a tap, so hauling a card up the
list no longer pops the expanded card view open under your finger. A
picked-up card swells and casts a shadow, which on touch is the only
confirmation the hold registered.

The up/down arrows stay as the precise alternative and grow to 46px
(40px on phones) now that they aren't sharing space with the handle.
2026-07-27 16:25:15 -04:00
Greyson Parrelli a2024229ff Hold the battle arena at a fixed height.
The play area grew and shrank as cards entered and left play. Two slots
were sized independently of the cards that fill them: the pet zone
reserved 150px for a 162px battle card, and the empty-deck placeholder
kept its desktop 84x116 on phones where the face-down card is 56x78. So
each faint/reveal moved the arena 12px per side on desktop, and a deck
running dry moved it 38px per side on a phone.

Every arena slot now derives from one set of --unit-*/--deck-* metrics on
.battle, and holds that size whether or not a card occupies it. Measured
across a battle's states (no pets, both revealed, one fainted, fans of
apples, decks dry), the arena height spread goes from 24px desktop /
76px phone to 0.

Also hide the arena's horizontal scrollbar: a wide apple fan made it
appear and vanish mid-battle, and with a content-driven height that alone
jumped the arena by the scrollbar's thickness. Touch, trackpad and
shift+wheel still scroll it.
2026-07-27 16:24:52 -04:00
Greyson Parrelli b5a143d059 Better desktop scaling. 2026-07-27 16:06:23 -04:00
Greyson Parrelli 4fb5c5929f Keep deck storted sensibly during shop phase. 2026-07-27 09:29:07 -04:00
Greyson Parrelli 1070999b95 Fix some card UX. 2026-07-27 00:03:23 -04:00
Greyson Parrelli 76e08ceb17 Improve drag and drop animation. 2026-07-26 23:27:20 -04:00
Greyson Parrelli 08a2e74067 Fix bug in drag and drop. 2026-07-26 22:47:04 -04:00
Greyson Parrelli 5de5b60660 Keep the phone topbar on one row, and tighten card corners.
- Force the topbar to a single row and let long player names truncate with an
  ellipsis, so the three-dot menu no longer wraps to a second line.
- Drop the card's outer corner radius from 14px to 9px so it matches the
  scene/panel boxes inside (7-8px) instead of dwarfing them.
2026-07-26 22:13:21 -04:00
Greyson Parrelli 5a846f1319 Suppress mobile long-press selection and tap highlight.
Treat the app as a game surface: no tap-flash, and a long-press on a card or
button no longer starts a text selection or pops an image callout. Form inputs
and the room code opt back into selection so typing and copying still work.
2026-07-26 21:52:39 -04:00
Greyson Parrelli 53a04b0cea Give phone shop cards description room and un-clip the selection.
The horizontal-scroll trays clip vertical overflow, so a selected card's lift,
gold outline, and check badge were cut off at the top. Add row headroom and
tuck the check badge inside the card corner. Also make the in-tray cards taller
with a larger rule panel and bigger ability text so descriptions aren't cramped
(widths stay tight so all four shop cards still fit without scrolling).
2026-07-26 21:49:40 -04:00
Greyson Parrelli 6e6374e751 Fix mobile card magnify: no phantom hover preview, larger art/power.
- A tap on a touch device synthesized mouseenter/mousemove and popped the
  hover magnifier on top of the tap-to-magnify overlay — a double image. Gate
  the hover preview on real hover capability ((hover: hover)) so touch taps
  only open the tap overlay.
- In that overlay the card is large, but its art, power badge, and text were
  still the tiny in-tray sizes; restore full-size art/power/damage/name/effect
  so the magnified card reads like a real card.
2026-07-26 20:50:38 -04:00
Greyson Parrelli 9a3ee34357 Add touch-friendly shop interactions on phones.
A phone has no hover to preview a card, so tapping now opens a magnified,
fully-readable view with the actions that fit it instead of acting blind:

- Shop card: tap to see it big, then Buy (or read it even when unaffordable).
- Your deck card: tap to see it big, then Sell it, or Select to enter a
  bulk-selection mode where taps toggle pets (no magnify) and the action bar
  offers Sell / Triple / Cancel.

Desktop keeps click-to-buy and click-to-select unchanged; the new behavior is
gated on a max-width:600px media query via a small useMediaQuery hook.
2026-07-26 15:22:41 -04:00
Greyson Parrelli 33bef8f58a Battle result dialog, speed toggle, and topbar refactor for mobile.
- End-of-battle result is now a centered dialog (Victory/Defeat/Draw) with
  'Next round' and 'Not yet'; 'Not yet' dismisses it to rewatch the battle,
  and a toolbar button remains to advance. A modal is always fully on screen,
  fixing the next-round button being unreachable below the arena on phones.
- Also make the play area genuinely scrollable on phones (stretch the body
  so table-main's overflow can engage) as a safety net.
- Collapse the 5-button playback speed picker into one button that cycles
  through the options, keeping the battle controls on a single row.
- Topbar: show the round as a die face (1-6 pips) on all screens, move the
  room code and Leave into a '...' dropdown menu, and drop the wordmark on
  phones so the rail stays one row (die + players + menu).
- On phones, strip battle cards to art + power/damage + name (no suit, tier,
  or ability text); the magnified view still shows the full card.
2026-07-26 15:15:18 -04:00
Greyson Parrelli de9bb480c2 Optimize the layout for phones in portrait.
Lock the app to the viewport on screens <=600px wide so the page itself
never scrolls: the topbar becomes a slim rail and the play area fills the
rest. Cards, trays, and type shrink so a shop round or a battle fits on
one screen; the shop and deck rows scroll sideways when a full six-pet
deck outgrows the width, keeping each tray's height fixed. Arrange is the
one screen allowed to scroll past the viewport, since a battle line can
run long.
2026-07-26 15:04:54 -04:00
Greyson Parrelli 4ed04c967b Improve snappiness and add speed setting. 2026-07-26 14:21:56 -04:00
Greyson Parrelli e3234b6f83 Enter to submit. 2026-07-25 23:13:40 -04:00
Greyson Parrelli 0bf9712c5e Improve drag and drop. 2026-07-25 22:14:05 -04:00
Greyson Parrelli e6c895d6b4 Use real assets. 2026-07-25 18:42:20 -04:00
Greyson Parrelli 3598180ff1 Improved card design. 2026-07-25 14:08:59 -04:00
Greyson Parrelli 3a7f92b3cb Allow abomination to mimic play abilitites. 2026-07-25 07:58:02 -04:00
Greyson Parrelli a1d57fe1dd Initial pass at unicorn pack. 2026-07-25 00:37:44 -04:00
Greyson Parrelli f3783b44bf Improve AI difficulty scaling. 2026-07-24 23:03:02 -04:00
Greyson Parrelli 5a396e6efe Improve AI to stop selling everything. 2026-07-24 22:34:55 -04:00
Greyson Parrelli 95499026d7 Move the UI to be vertical. 2026-07-24 22:16:28 -04:00
Greyson Parrelli 0a1e2f9bee Make the AI a little smarter. 2026-07-24 16:20:45 -04:00
Greyson Parrelli e25a85e394 Fix bugs around AI opponents. 2026-07-24 12:52:10 -04:00
Greyson Parrelli add2218978 More random UI fixes. 2026-07-24 11:23:38 -04:00
Greyson Parrelli 6558806ba0 Various bug fixes and improvements. 2026-07-24 10:47:59 -04:00
Greyson Parrelli 0fe0757e18 Fix nurse shark and remove mid-battle choice. 2026-07-24 10:12:17 -04:00
Greyson Parrelli 094f38593e Fix a bunch of bugs. 2026-07-24 09:51:25 -04:00
Greyson Parrelli ceab30dc2e Add ability to hover pets in event log. 2026-07-24 09:23:25 -04:00
Greyson Parrelli 10b6346874 More UX improvements. 2026-07-24 09:07:54 -04:00
Greyson Parrelli 962e3bb5ff Various UX improvements. 2026-07-24 07:54:58 -04:00
Greyson Parrelli dd395f4bbf Initial pass at Golden Pack. 2026-07-24 07:47:05 -04:00
Greyson Parrelli e74f983470 Add lobby and pack concept. 2026-07-23 22:01:54 -04:00
Greyson Parrelli 9d9acc4577 Improved battle animations. 2026-07-23 21:39:01 -04:00
Greyson Parrelli ce70b1d89f Move a warning element down. 2026-07-23 21:28:06 -04:00
Greyson Parrelli 3e34e9b293 Improve some animations. 2026-07-23 21:24:30 -04:00
Greyson Parrelli 72e198a750 Fix shop action costs and pass semantics.
Only buying costs gold; selling and trading (Triple) are free. Pass is
now a final action, legal only at or under the pet limit: it forfeits
remaining gold and ends that player's shopping for the round, with the
shop closing once everyone has passed. That makes the separate cleanup
phase unreachable (you sell down in-shop before passing), so it is
removed. The client asks for confirmation before passing, and the bot
knows buys are the only coin sink, when passing is legal, and that it
must sell down before it can pass.
2026-07-23 16:11:07 -04:00
Greyson Parrelli db1a6ef290 Add bot to play against. 2026-07-23 15:58:12 -04:00
Greyson Parrelli 3825dbacec Improve arrangement phase UI. 2026-07-23 15:26:29 -04:00
Greyson Parrelli 547cd81a99 Various UX improvements. 2026-07-23 11:55:12 -04:00
Greyson Parrelli 816ad13f7e Improve rock attribution. 2026-07-23 11:17:56 -04:00
Greyson Parrelli 235b1d9cc8 Improve UI of food and set-aside cards. 2026-07-23 11:12:47 -04:00
Greyson Parrelli 7bb20e5d2d Improve dice rolls. 2026-07-23 10:26:15 -04:00