vv webcam Unit 2: the Chat scene in the vertical tier - rect only, tile or one whole 607x540 area

The creator's locked table (2026-10-17) gives the Chat scene its own rules in
the 9:16 tier: RECT ONLY - the circle option is not offered - and a size that
is either the normal small tile or ENLARGED to fill one whole 607x540 area
(top or bottom). Unit 1 shipped the per-scene placement; this unit is the Chat
scene's own variant of it.

The rule lives on the MODEL, not on the button:
- Models/SceneElement.cs: ClipShape and ToggleClipShape() are now virtual.
- Models/WebcamSceneConfig.cs: VerticalShapeLocked (set per scene by the VM)
  OVERRIDES the ClipShape property, so no writer can slip a circle in - the
  toggle, the Shape button and the placement swap all go through it. The lock
  is cleared BEFORE the 16:9 layout comes back, so the desktop shape returns.
- ViewModels/MainViewModel.Webcam.cs: CanToggleClipShape (the circle is NOT
  offered in the vertical Chat layout - the Shape button disappears, it is not
  merely greyed out), IsChatSceneCamera, ResizeWebcamInVerticalTier.
- Models/VerticalCameraLayout.cs: FillsArea (the "enlarged" state, derived -
  no new column) and SizeFor - the Chat camera's TWO sizes, the tile or the
  whole area, whichever is nearer the requested width, so the resize handle
  has two detents instead of any size in between.
- An enlarged camera FILLS the area its centre is in (top or bottom), so
  dragging it up/down swaps the areas.
- The Chat camera is auto-tiled like the Live one when the vertical tier is
  picked - otherwise the vertical chat stream has no camera at all.
- Controls/PreviewPane.xaml.cs: the resize routes through the VM; the drag
  assigns, lets the model clamp into the band, then snaps (so the enlarged
  camera can be dragged from the top area to the bottom one).

Test: ytLive.Tests/VerticalChatCameraLayoutTests.cs - the ONE Good Dog test for
the unit: the vertical tier is picked -> the Chat camera comes into the band as
a small RECT tile -> the circle option is not offered and cannot be set even on
the model -> dragged up and enlarged it fills the TOP area exactly -> back to
16:9 the desktop layout is restored exactly and the circle option is offered
again. 430/430 tests pass, 0 warnings.

Research (the creator's table is the established practice, not our invention):
- Streamlabs' vertical guide: "splitting the screen in half horizontally,
  placing the camera feed in the top half and the main content on the bottom
  (or vice versa) may be the bet", and a just-chatting vertical wants the
  camera "to take up most of the screen"
  (streamlabs.com/content-hub/post/overlays-vertical-and-horizontal-streaming)
- Bloopbot's vertical overlay docs describe the same per-layer model we use at
  scene granularity: "move or resize a layer on Vertical and it stops being
  Auto-placed. It keeps the place you gave it, and the horizontal layout is not
  touched" (bloopbot.com/docs/vertical-overlays-twitch-dual-format) - our
  swap-at-tier-change, stored per scene.
- Landmine recorded: "about the bottom 560 px of the vertical video can be
  covered by Twitch's chat and player controls on phones" (Bloopbot) - the Chat
  camera's enlarged BOTTOM area may be half-hidden by the platform chrome;
  TASK 53's safe-zone work decides that.

Memory in the same commit: ai.md (the Chat rules, the shape lock, the tests),
TASKS.md + TASKS/task-57-vertical-camera-layout.md (TASK 57 complete), HANDOFF.md,
MyMistakes.md (3 recipes: lock the model property not the UI button; two detents
for a discrete size set; the edit tool cannot match an oldString with an em
dash), Models/ViewModels/Controls index rows.
This commit is contained in:
2026-10-21 19:23:29 -07:00
parent ccc1db52d3
commit 3a77662a95
17 changed files with 415 additions and 66 deletions
+37 -6
View File
@@ -2,7 +2,8 @@
> Catalog: [`TASKS.md`](../TASKS.md) — status and requirements live here.
**Status:** 🔶 Unit 1 shipped 2026-10-21 (the Live scene). **Unit 2 open** (the Chat scene).
**Status:** ✅ Both units shipped 2026-10-21 (Unit 1 = the Live scene, Unit 2 = the Chat scene).
Only the creator's hands-on check (slice 3) is outstanding.
## Why
The vertical tier (1080×1920) is a centred **band crop** of the same 1920×1080 master every
@@ -16,7 +17,7 @@ not in the picture. Switching tiers must not cost the creator their camera.
|---|---|---|---|
| 16:9 | as today | as today | as today |
| **vv · Live** | circle **or** rect, the creator's choice | small tile | one of **six** spots: top/bottom × left/centre/right |
| vv · Chat | rect only | normal, or enlarged to one 607×540 area | the same six spots (Unit 2) |
| vv · Chat | rect only | normal, or enlarged to one 607×540 area | the same six spots; enlarged fills the top or the bottom area |
| Starting / BRB / Ending | unchanged | unchanged | unchanged |
Plus: each scene keeps its **own** vertical position, size and shape; switching back to 16:9
@@ -47,23 +48,53 @@ restores the desktop layout **exactly**; placement is set by drag with snap (lik
- **Manual entry.** The webcam's Layers properties gained a Geometry section (X/Y/W/H) bound to
the **live** placement — the one the current tier shows.
## Design (Unit 2 — the Chat scene)
- **Rect only, and the lock sits on the model.** `WebcamSceneConfig.VerticalShapeLocked` (set per
scene by the VM) **overrides the `ClipShape` property**, so a locked camera cannot become Round
by ANY writer — the toggle, the Shape button, the placement swap. The lock is cleared *before*
the 16:9 layout comes back, so the desktop shape is restored.
- **The circle is not offered.** `MainViewModel.CanToggleClipShape` is false for a Chat camera in
the vertical tier → the Shape button in the webcam's properties disappears (not just disabled).
- **Two sizes, snapped by the nearer one.** `VerticalCameraLayout.SizeFor(band, requestedWidth)`
returns the small tile (270×152) or one whole area (607.5×540) — whichever is nearer the
requested width, so the resize handle has two detents instead of any size in between.
- **An enlarged camera fills the area its centre is in** — the top one or the bottom one
(`VerticalCameraLayout.AreaFor`).
- **The Chat camera is auto-tiled** like the Live one when the vertical tier is picked — otherwise
the vertical chat stream has no camera at all.
## Slices (one integration test each)
1. ✅ **Unit 1 — the Live scene** (shipped 2026-10-21): the vertical tier brings the Live camera
into the band as a small tile; dragging it to the top-right snaps it top-right inside the
band; switching back to 16:9 restores the desktop layout exactly; both placements survive a
save + reload. `ytLive.Tests/VerticalWebcamLayoutTests.cs` — the ONE test for the unit.
2. ☐ **Unit 2 — the Chat scene**: rect only (no circle) in the vertical tier, either the normal
size or enlarged to fill one 607×540 area; the same six-spot snap. The Chat scene's 16:9
exemption from the half-frame cap must not leak into the vertical tier.
2. ✅ **Unit 2 — the Chat scene** (shipped 2026-10-21): in the vertical tier the Chat camera comes
into the band as a small RECT tile; the circle option is not offered and cannot be set even on
the model; enlarged it fills one whole 607×540 area — the top one or the bottom one, by where
the camera is; switching back to 16:9 restores the desktop layout exactly and the circle option
is offered again. `ytLive.Tests/VerticalChatCameraLayoutTests.cs` — the ONE test for the unit.
3. ☐ **Creator check** (needs the creator's hands): switch the dropdown to "Vertical 1080p60",
confirm the camera tile lands inside the band and the Shape button toggles circle/rect in the
vertical tier, then switch back and confirm the desktop layout is untouched.
vertical tier (and is gone in the Chat scene), enlarge the Chat camera to see it fill a whole
area, then switch back and confirm the desktop layout is untouched.
## Notes
- OBS cannot do this (no per-aspect layout storage — the maintainers' answer is a second scene
fed as a source); Streamyard documents the same gap. Our per-scene, per-tier stored placement
resolved on the tier change is the step past both.
- **Research (Unit 2, 2026-10-21).** The "one 607×540 area" rule is the established vertical-stream
layout: Streamlabs' vertical guide says "splitting the screen in half horizontally, placing the
camera feed in the top half and the main content on the bottom (or vice versa) may be the bet",
and that a just-chatting vertical wants the camera "to take up most of the screen"
(streamlabs.com/content-hub/post/overlays-vertical-and-horizontal-streaming). Bloopbot's vertical
overlay docs describe the same per-layer model we use at scene granularity: "move or resize a
layer on Vertical and it stops being Auto-placed. It keeps the place you gave it, and the
horizontal layout is not touched" (bloopbot.com/docs/vertical-overlays-twitch-dual-format).
- ⚠️ **Landmine for the bottom area:** "about the bottom 560 px of the vertical video can be covered
by Twitch's chat and player controls on phones" (Bloopbot, above) — the Chat camera's enlarged
**bottom** area may be half-hidden by the platform chrome. TASK 53's safe-zone work decides that.
- The vertical tier's output crop is TASK 53's business (safe zones, caption clearance); the
camera tile is inside the band, but the band is not yet proven against TikTok/Shorts chrome.