Shelf: scene packs #244

Closed
opened 2026-07-22 02:59:04 +00:00 by claude-bot · 1 comment
Contributor

Let the GM bundle ShelfCards into named scenes during prep and swap the shelf's active scene in one tap during play; cards keep their positions. (#235)

Let the GM bundle ShelfCards into named scenes during prep and swap the shelf's active scene in one tap during play; cards keep their positions. (#235)
Author
Contributor

Done — merged in PR #264 (c699721), CI green.

Scene packs turned out to need no new table and no migration: the scene tag has been on ShelfCard since #239, so a scene is simply the set of cards carrying that name. Creating one is tagging a card; a scene stops existing when its last card leaves it. The scene bar is derived from the cards themselves.

Backend — one real gap. Every field on ShelfCardUpdate uses None for "leave unchanged", so a card could join a scene and never leave it. An empty/blank string is now the clear sentinel, and names are stored stripped so " Docks" and "Docks" are one chip rather than two.

Frontend — a scene bar (All / per-scene chips with counts / Unfiled), hidden entirely until something is tagged so an untagged shelf looks as it did; and a per-card scene picker with + New scene….

The interesting part was the guardrail. Filtering hides cards, it never moves them — a hidden card's stored x/y is untouched, so swapping back restores the exact layout the GM left (#235's "never auto-move the GM's cards"). Cards also keep their index in the full list while filtered, so a never-placed card's cascade fallback position doesn't drift between scenes.

Three surfaces that index the board had to follow:

  • 19 and the stage's prev/next walk the visible scene, so "the Nth card" means the Nth one on screen.
  • A staged card stays staged across a scene swap — the stage is "now playing", not a view of the board.
  • A Ctrl-K hit from another scene swaps the board to that scene, otherwise the stage would have no board card behind it.

Tested: backend 777 passed (1 new case covering strip / leave-unchanged / clear), frontend 413 passed (new SessionShelf.test.jsx, 7 cases), ruff + eslint clean.

🤖 Generated with Claude Code

Done — merged in **PR #264** (`c699721`), CI green. Scene packs turned out to need **no new table and no migration**: the `scene` tag has been on `ShelfCard` since #239, so a scene is simply the set of cards carrying that name. Creating one is tagging a card; a scene stops existing when its last card leaves it. The scene bar is derived from the cards themselves. **Backend** — one real gap. Every field on `ShelfCardUpdate` uses `None` for "leave unchanged", so a card could join a scene and never leave it. An empty/blank string is now the clear sentinel, and names are stored stripped so `" Docks"` and `"Docks"` are one chip rather than two. **Frontend** — a scene bar (`All` / per-scene chips with counts / `Unfiled`), hidden entirely until something is tagged so an untagged shelf looks as it did; and a per-card scene picker with `+ New scene…`. The interesting part was the guardrail. Filtering **hides** cards, it never moves them — a hidden card's stored x/y is untouched, so swapping back restores the exact layout the GM left (#235's "never auto-move the GM's cards"). Cards also keep their index in the *full* list while filtered, so a never-placed card's cascade fallback position doesn't drift between scenes. Three surfaces that index the board had to follow: - `1`–`9` and the stage's prev/next walk the **visible** scene, so "the Nth card" means the Nth one on screen. - A staged card **stays staged** across a scene swap — the stage is "now playing", not a view of the board. - A Ctrl-K hit from another scene swaps the board to that scene, otherwise the stage would have no board card behind it. Tested: backend 777 passed (1 new case covering strip / leave-unchanged / clear), frontend 413 passed (new `SessionShelf.test.jsx`, 7 cases), ruff + eslint clean. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign in to join this conversation.
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
rbrooks/Quest-Board#244
No description provided.