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
+47 -22
View File
@@ -1,9 +1,10 @@
# HANDOFF — 2026-10-21 (vv webcam Unit 1 shipped; the previous HA-lights session's state below)
# HANDOFF — 2026-10-21 (vv webcam Units 1+2 shipped; the previous HA-lights session's state below)
## At a glance
- **Branch** main, tracking `origin/main`. **origin/main = `6be062c` = HEAD — up to date, nothing
waiting.** The vv Unit 1 commit was **pushed on the creator's approval** (2026-10-21, after the
creator tested the placement). Push only at sub-milestones/milestones, at the creator's word.
- **Branch** main, tracking `origin/main`. **origin/main = `ccc1db5` = the last pushed commit; the
vv Unit 2 work is committed on top of it.** The vv Unit 1 commit was **pushed on the creator's
approval** (2026-10-21, after the creator tested the placement). Push only at
sub-milestones/milestones, at the creator's word.
- **The push path changed:** `origin` is now
`https://llgit.llamachile.tube/gramps/LlamaCasty.git` (HTTPS + the credential helper
`/home/gramps/bin/gitea-credential`, which reads the password from the gitignored
@@ -11,9 +12,12 @@
was **renamed `gramps/ytLlive` → `gramps/LlamaCasty`**, and `llgit:2214` refuses the publickey
of this machine's key even though it IS registered (account key id 6 "Corsair VSC"). Ask the
Gitea REST API, don't do key archaeology — recipe in `MyMistakes.md` → 2026-10-21.
- **This session shipped vv webcam Unit 1** (the vertical 9:16 tier keeps its OWN camera placement per
scene; 16:9 restores the desktop layout exactly). Code + memory in ONE commit; the ONE Good Dog test
is `ytLive.Tests/VerticalWebcamLayoutTests.cs`. **Unit 2 (vv · Chat) is next** — see the vv section.
- **This session shipped vv webcam Units 1+2** (the vertical 9:16 tier keeps its OWN camera placement
per scene; 16:9 restores the desktop layout exactly; the Chat scene in vv is rect-only and can be
enlarged to fill a whole 607×540 area). Code + memory in ONE commit each; the ONE Good Dog tests
are `ytLive.Tests/VerticalWebcamLayoutTests.cs` (Unit 1) and
`ytLive.Tests/VerticalChatCameraLayoutTests.cs` (Unit 2). **Only the creator's hands-on check is
left** — see the vv section.
- **The previous session (HA lights) produced NO ytLive code** — it was spent on the creator's Home
Assistant light alert system (off-repo, `192.168.50.145`). See `MyMistakes.md` → 2026-10-21: the plan
was one tweak to a verified-working script; the script was rewritten twice, the alert path broke, and
@@ -58,7 +62,7 @@ Zombie entities deleted from the registry: `script.leak_strobe`, `script.doorbel
"unavailable" claim was a bad read during a reload; `alert_leak_on` now also triggers on the latched
`sensor.pump_leak_last_water_leak_alert`.
## vv webcam feature — locked rules (creator, 2026-10-17) — **Unit 1 shipped 2026-10-21**
## vv webcam feature — locked rules (creator, 2026-10-17) — **Units 1+2 shipped 2026-10-21**
| mode | shape | size | position |
|---|---|---|---|
| 16:9 | as today | as today | as today |
@@ -114,6 +118,28 @@ Zombie entities deleted from the registry: `script.leak_strobe`, `script.doorbel
VM's snap instead of free-floating over the master.
- Test seam: the drag lives in a **VM method**, so the test drives it without synthesising mouse input.
### What shipped in Unit 2 (the Chat scene, 2026-10-21) — do not re-hunt
- **Rect only, and the lock is on the MODEL, not the UI.** `WebcamSceneConfig.VerticalShapeLocked`
(set per scene by the VM) **overrides the `ClipShape` property** → a locked camera cannot become
Round by any writer (the toggle, the Shape button, the placement swap). `SceneElement.ClipShape`
and `SceneElement.ToggleClipShape()` are `virtual` for this. 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).
`MainViewModel.cs` raises it on the selection change; `MainViewModel.Streaming.cs` on the tier change.
- **Two sizes, snapped by the nearer one:** `VerticalCameraLayout.SizeFor(band, requestedWidth)` →
the small tile (270×152) or one whole area (607.5×540). The resize handle therefore has two
detents instead of any size in between.
- **An enlarged camera fills the area its centre is in** — top or bottom (`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). `ResolveVerticalCameraLayout` now auto-tiles Live **and**
Chat; Starting/BRB/Ending keep their 16:9 placement.
- The preview's resize routes through `MainViewModel.ResizeWebcamInVerticalTier` (the Chat camera's
discrete size + the snap); the drag routes through `MoveWebcamInVerticalTier` (assign → clamp →
snap, so the enlarged camera can be dragged from the top area to the bottom one).
- *Test:* `ytLive.Tests/VerticalChatCameraLayoutTests.cs` — **PASSES** (in Chat under the vertical
tier, enlarging fills the full top area and the circle option is not offered).
### Units (each: ONE Good Dog integration test, own commit, memory in the same commit)
1. ✅ **vv camera layout (Unit 1)** — shipped 2026-10-21. Stored separately per scene, resolved when the
tier changes. Live: small tile (circle or rect) snapped to one of six spots; drag like the socials +
@@ -121,21 +147,18 @@ Zombie entities deleted from the registry: `script.leak_strobe`, `script.doorbel
*Test:* `ytLive.Tests/VerticalWebcamLayoutTests.cs` — with the vertical tier active, dragging the Live
camera to top-right places it top-right inside the band; switching back to 16:9 restores the original
layout exactly; both placements survive a save + reload. **PASSES.**
2. ☐ **vv · Chat (Unit 2)** — rect enforced with the circle option unavailable, plus enlarge-to-one-area
(607×540) snapping top or bottom.
*Test:* in Chat under the vertical tier, enlarge sets the full top area and the circle option is not
offered. **Not started.**
2. ✅ **vv · Chat (Unit 2)** — shipped 2026-10-21. Rect enforced with the circle option unavailable, plus
enlarge-to-one-area (607×540) filling the top or the bottom area by where the camera is.
*Test:* `ytLive.Tests/VerticalChatCameraLayoutTests.cs` — in Chat under the vertical tier, enlarge sets
the full top area and the circle option is not offered. **PASSES.**
## Next step
- **vv Unit 2 (the Chat scene)** — the only queued piece of this feature. Requirements are locked in
`TASKS/task-57-vertical-camera-layout.md`: rect ONLY in the vertical tier (no circle option offered),
size either normal or enlarged to fill one 607×540 area, same six-spot snap; and the Chat scene's
16:9 exemption from the half-frame cap (`MaxWebcamWidthFor/HeightFor`) must not leak into the
vertical tier.
- **Creator check (needs the creator's hands):** switch the resolution dropdown to "Vertical 1080p60",
confirm the Live camera tile lands inside the band and the Shape button toggles circle/rect there,
then switch back and confirm the desktop layout is untouched. The unit test covers the geometry, not
the eyeball.
- **Creator check (needs the creator's hands)** — the last piece of the vv feature: switch the
resolution dropdown to "Vertical 1080p60", confirm the Live camera tile lands inside the band and
the Shape button toggles circle/rect there, open the **Chat** scene and confirm the Shape button is
**gone** (rect only) and that dragging the tile up and enlarging it fills a whole 607×540 area, then
switch back and confirm the desktop layout is untouched. The unit tests cover the geometry, not the
eyeball.
- Nothing else is queued for llamacasty — the creator queues work.
## Open (operational)
@@ -163,7 +186,9 @@ Zombie entities deleted from the registry: `script.leak_strobe`, `script.doorbel
- TASK 55 disk hygiene (`startup.log` uncapped — 23MB and growing every 5s).
## Tests
- Last full run: **429/429 passed, 0 warnings** (2026-10-21, this session — the vv Unit 1 gate run).
- Last full run: **429/430 passed, 0 warnings** (2026-10-21, this session — the vv Unit 2 gate run).
The one failure was `LayerReorderPersistenceTests.RealMouseDrag_OnTheLayerList_PersistsTheReorder`,
which **passes in isolation** (re-run: 3/3) — the known real-mouse flake, not a regression.
- Known flaky-by-environment (all pass in isolation): `AudioPipelineTests.Mix_HonorsProviderGains…`,
`MasterLimiter_CapsTheLiveMix_OnThePipe`, `LayerReorderPersistenceTests.RealMouseDrag…`,
`Round_Clip_Corner…`.