Slot budget (#47) #98

Merged
crowmaki merged 2 commits from issue-47-slot-budget into main 2026-10-08 20:36:31 +00:00
Owner

Closes #47.

The app fills H3's 9 image and 3 audio slots for every Shot and shows what it dropped (User Stories 64, 88, 89 and 108–116, decisions in #10). The prompt composer (#48) and the job builder (#51) read the filled assignment from shot_slots.

What changed

  • Schema v19.

    • shot_slot_item(shot_id, medium, position, candidate_key, placed, arrived) holds an edited Slot list. No rows for a medium means the Shot follows the Project order live.
    • shot gains board_per_panel and board_clean.
    • setup_subject gains atlas_group, and setup gains atlas_size (native or a pixel budget; NULL follows the Project).
    • packed_prop is a content-keyed cache like atlas (ADR-0005).
    • Shot and Setup deletes take the slot rows along, and undo restores them.
  • Candidates (slots.rs). Only locked references count. Images come in the Project category order:

    • Keyframes, start → times → end
    • Atlases from the Setup's grouping
    • Wardrobe mannequins, each right after its Look's Atlas while the two categories are adjacent
    • the Setup's location angle, if the current snapshot picks it
    • the Board
    • Props, in order of first mention in the action text

    Audio is the Voice references of the speakers, by first Line. Silent subjects' voices are listed below the line, so they can be dragged up.

  • Filling. Items above the line are sent while they fit. Once one doesn't fit, it and everything after it is over budget. A one-slot-per-Panel Board falls back to one tiled slot before anything is dropped. Slot numbers count the sent items in list order, and a per-Panel Board takes consecutive ones.

  • Edited lists.

    • set_shot_slot_list saves a medium's full order with placements, and refuses a list that doesn't name every candidate once.
    • A new candidate goes in at its default position, badged new. It only takes slots the user's placements leave over.
    • mark_shot_slots_seen clears the badges without changing what is sent. Seen arrivals are stored as arrived and keep their lower priority until the next edit.
    • reset_shot_slot_list returns both media to the Project order.
    • Edits are undoable. Marking seen is not.
  • Atlases per Setup (atlas_groups.rs).

    • The default grouping is first-fit in subject order: up to three Looks per Atlas, same Parity only.
    • set_setup_atlas_groups regroups the Looks within Parity, and set_setup_atlas_size overrides the Atlas size.
    • Setups with the same snapshots and size share one cached Atlas.
  • Packed Prop (packed_prop.rs). A Prop's snapshot Tiles go side by side in uniform cells sized to the largest Tile, fitted on mid-grey, at most 1 MP, never upscaled. Same snapshot, same bytes.

  • Category order. set_reference_category_order is undoable, and the order is on ProjectDto.

  • UI.

    • Project settings → Slot order: drag-and-drop list, plus ↑/↓ buttons.
    • Per Shot in the Scenes view, a Slots block:
      • drag rows or the sent line, or use Send/Exclude
      • New, Excluded and over-budget badges
      • Board per-panel and clean toggles
      • Reset to Project order
    • Per Setup, an Atlases block: size override, and a move-to-Atlas picker for each Look.
    • A red +N over chip (ADR-0006) on the Shot in the Setups list, on the Board header and on the Board timeline.
    • Dragging uses pointer events (DragList.svelte), because the webview gives HTML5 drag and drop to file drops.

Decisions worth a look

  • Over budget is a count (over_budget: u32) so the chip can say +N over, per ADR-0006.
  • arrived flag. The spec's is_new is computed, not stored: a candidate with no row is new. arrived keeps a seen arrival from overtaking the user's placements, which the first cut got wrong (caught in review).
  • The UI's single line. Saving from the UI writes the order as sent items, then the rest. Excluded items can't sit between placed ones in the UI, although the core allows it.

Not in this PR

  • Joining a Voice snapshot's clips into one file, rendering the tiled Board, and applying the clean-sketch toggle: these happen at job build (#51). This PR stores the choices and exposes them.
  • The "sent set changed" marker comes with #48/#49. Dailies' sent assignment and Take recording come with #51/#55. The queue dialog badge waits for the queue dialog.
  • Performance slice and dropping Voice references: there is no Performance in the core yet (#63/#65).
  • App-wide default order: it seeds new Projects but can't be edited in app Settings. There is no app Settings UI yet.

Known trade-offs

  • Script reads compute slots. Every script read and scene_setups resolve the slots of every Shot to fill the chip. That is fine at slice scale; a cache can come later if it shows up.
  • Undo after marking seen. Undoing an edit made before a Slot list was marked seen writes back the older rows, so New badges can reappear. What is sent stays right.

Testing

  • crates/studio-core/tests/slot_budget.rs has 20 tests. They cover:
    • category order and its undo
    • resolution order and mannequin interleaving
    • overflow and the over-budget count on Shot and Board views
    • per-Panel Board and its tiled fallback
    • edited-list rules: new, seen, removed, reset, undo, validation, and that viewing never changes the sent set
    • audio speakers and silent subjects
    • Atlas grouping, regrouping, size override and sharing
    • packed Prop bytes and caching
  • src/lib/scenes/slots.test.ts and setups.test.ts cover drag, line and regroup logic.
  • cargo test --workspace --all-features, bun test src and bun run check all pass. Clippy is clean apart from an existing type_complexity warning in api.rs.
  • Checked in the running app: the Slot list with a 3-Panel Board, Exclude and undo, and drag-reordering the Slot order page.
Closes #47. The app fills H3's 9 image and 3 audio slots for every Shot and shows what it dropped (User Stories 64, 88, 89 and 108–116, decisions in #10). The prompt composer (#48) and the job builder (#51) read the filled assignment from `shot_slots`. ## What changed - **Schema v19.** - `shot_slot_item(shot_id, medium, position, candidate_key, placed, arrived)` holds an edited Slot list. No rows for a medium means the Shot follows the Project order live. - `shot` gains `board_per_panel` and `board_clean`. - `setup_subject` gains `atlas_group`, and `setup` gains `atlas_size` (`native` or a pixel budget; NULL follows the Project). - `packed_prop` is a content-keyed cache like `atlas` (ADR-0005). - Shot and Setup deletes take the slot rows along, and undo restores them. - **Candidates** (`slots.rs`). Only locked references count. Images come in the Project category order: - Keyframes, start → times → end - Atlases from the Setup's grouping - Wardrobe mannequins, each right after its Look's Atlas while the two categories are adjacent - the Setup's location angle, if the current snapshot picks it - the Board - Props, in order of first mention in the action text Audio is the Voice references of the speakers, by first Line. Silent subjects' voices are listed below the line, so they can be dragged up. - **Filling.** Items above the line are sent while they fit. Once one doesn't fit, it and everything after it is over budget. A one-slot-per-Panel Board falls back to one tiled slot before anything is dropped. Slot numbers count the sent items in list order, and a per-Panel Board takes consecutive ones. - **Edited lists.** - `set_shot_slot_list` saves a medium's full order with placements, and refuses a list that doesn't name every candidate once. - A new candidate goes in at its default position, badged new. It only takes slots the user's placements leave over. - `mark_shot_slots_seen` clears the badges without changing what is sent. Seen arrivals are stored as `arrived` and keep their lower priority until the next edit. - `reset_shot_slot_list` returns both media to the Project order. - Edits are undoable. Marking seen is not. - **Atlases per Setup** (`atlas_groups.rs`). - The default grouping is first-fit in subject order: up to three Looks per Atlas, same Parity only. - `set_setup_atlas_groups` regroups the Looks within Parity, and `set_setup_atlas_size` overrides the Atlas size. - Setups with the same snapshots and size share one cached Atlas. - **Packed Prop** (`packed_prop.rs`). A Prop's snapshot Tiles go side by side in uniform cells sized to the largest Tile, fitted on mid-grey, at most 1 MP, never upscaled. Same snapshot, same bytes. - **Category order.** `set_reference_category_order` is undoable, and the order is on `ProjectDto`. - **UI.** - Project settings → Slot order: drag-and-drop list, plus ↑/↓ buttons. - Per Shot in the Scenes view, a Slots block: - drag rows or the sent line, or use Send/Exclude - New, Excluded and over-budget badges - Board per-panel and clean toggles - Reset to Project order - Per Setup, an Atlases block: size override, and a move-to-Atlas picker for each Look. - A red `+N over` chip (ADR-0006) on the Shot in the Setups list, on the Board header and on the Board timeline. - Dragging uses pointer events (`DragList.svelte`), because the webview gives HTML5 drag and drop to file drops. ## Decisions worth a look - **Over budget is a count** (`over_budget: u32`) so the chip can say `+N over`, per ADR-0006. - **`arrived` flag.** The spec's `is_new` is computed, not stored: a candidate with no row is new. `arrived` keeps a seen arrival from overtaking the user's placements, which the first cut got wrong (caught in review). - **The UI's single line.** Saving from the UI writes the order as sent items, then the rest. Excluded items can't sit between placed ones in the UI, although the core allows it. ## Not in this PR - Joining a Voice snapshot's clips into one file, rendering the tiled Board, and applying the clean-sketch toggle: these happen at job build (#51). This PR stores the choices and exposes them. - The "sent set changed" marker comes with #48/#49. Dailies' sent assignment and Take recording come with #51/#55. The queue dialog badge waits for the queue dialog. - **Performance slice and dropping Voice references:** there is no Performance in the core yet (#63/#65). - **App-wide default order:** it seeds new Projects but can't be edited in app Settings. There is no app Settings UI yet. ## Known trade-offs - **Script reads compute slots.** Every script read and `scene_setups` resolve the slots of every Shot to fill the chip. That is fine at slice scale; a cache can come later if it shows up. - **Undo after marking seen.** Undoing an edit made before a Slot list was marked seen writes back the older rows, so New badges can reappear. What is sent stays right. ## Testing - `crates/studio-core/tests/slot_budget.rs` has 20 tests. They cover: - category order and its undo - resolution order and mannequin interleaving - overflow and the over-budget count on Shot and Board views - per-Panel Board and its tiled fallback - edited-list rules: new, seen, removed, reset, undo, validation, and that viewing never changes the sent set - audio speakers and silent subjects - Atlas grouping, regrouping, size override and sharing - packed Prop bytes and caching - `src/lib/scenes/slots.test.ts` and `setups.test.ts` cover drag, line and regroup logic. - `cargo test --workspace --all-features`, `bun test src` and `bun run check` all pass. Clippy is clean apart from an existing `type_complexity` warning in `api.rs`. - Checked in the running app: the Slot list with a 3-Panel Board, Exclude and undo, and drag-reordering the Slot order page.
Fill H3's 9 image and 3 audio slots per Shot in the Project's category
order, with an editable per-Shot Slot list, per-Setup Atlas grouping and
size override, packed Prop images and over-budget badges.
Seen arrivals keep filling only what the user's placements leave over,
so opening a Slot list never changes what is sent. Once an item does
not fit, nothing after it is sent. The over-budget chip shows the
number of forced drops (+N over), per ADR-0006.
crowmaki deleted branch issue-47-slot-budget 2026-10-08 20:36:31 +00:00
Sign in to join this conversation.
No description provided.