fix(web): composite consumes the FULL canvas, alpha crop is measure-only — transparent web margins reveal the webcam again
take-19-2/take-20 'webcam black square under the web widget': the capture was alpha-cropped (FindContentBounds) and that CROP was fed to the compositor, whose UniformToFill zoomed the opaque content box to cover the whole element rect the moment the widget drew any content (idle transparent page = full-frame crop = the correct viewport, hence take-1-good/take-2-bad). OBS model verified: the page is a fixed 1920x1080 canvas and the element rect is a viewport onto it — measure with the alpha crop (preview/selection), hand the composite the FULL canvas on an 8-deep ring + Epoch (same identity discipline as camera/screen). Regression test: Composite_FullCanvasWebSource_TransparentMarginsRevealWebcam (the reveal contract: margin pixel = webcam, badge pixel = widget).
This commit is contained in:
+34
-1
@@ -15,7 +15,40 @@
|
||||
|
||||
## 🔬 Recipes registry
|
||||
|
||||
### Shrink / re-encode an image for the README (screenshots → small hero image)
|
||||
### Web-overlay transparency: measure with the alpha crop, COMPOSE with the full canvas
|
||||
|
||||
(2026-09-05, take-19-2/take-20 — "the webcam is a black square under the web widget".
|
||||
|
||||
**Symptom:** WebView2-based web overlays (StreamElements alert hosts etc.) rendered
|
||||
with hard opaque boxes over the webcam in the RECORDING but the preview looked fine,
|
||||
and the FIRST take after a rebuild was good but later takes went opaque — a
|
||||
stateful-looking bug.
|
||||
|
||||
**Root cause:** the capture was alpha-CROPPED to the widget's content bounding box
|
||||
(`FindContentBounds` — every non-zero-alpha pixel) and that CROP was handed to the
|
||||
compositor, which `UniformToFill`-scales a source into the element rect. A crop has
|
||||
NO transparent margins by construction, so the composite zoomed the opaque content
|
||||
to cover the ENTIRE element rect (hard box!) whenever the widget drew anything. It
|
||||
looked stateful because an idle/transparent page yields a full-frame crop ≈ the
|
||||
correct full-canvas viewport (good), while any real content yields a tight crop +
|
||||
zoom (bad).
|
||||
|
||||
**The rule (OBS browser-source model):** the page is a FIXED canvas (1920×1080 here);
|
||||
the element rect is a VIEWPORT onto it. Measure/select with the alpha crop; hand the
|
||||
composite the FULL canvas with its transparent background intact — `UniformToFill`
|
||||
then maps the page region 1:1 into the element rect and the page's transparent
|
||||
margins reveal the layers beneath (the webcam). When feeding a compositor that
|
||||
scales sources to fill a rect, NEVER feed it a crop of your source unless the rect
|
||||
is meant to re-frame it.
|
||||
|
||||
Recipe:
|
||||
1. Keep `FindContentBounds` for the preview bitmap / selection bounding box.
|
||||
2. Feed the compositor a full-canvas frame whose background is alpha 0, from an
|
||||
8-deep ring (same identity/Epoch discipline as every producer — a single reused
|
||||
scratch array tears under the consumer).
|
||||
3. Pin the reveal contract with a compositor test: full-canvas transparent-margin
|
||||
frame over a webcam rect → margin pixel = webcam color, opaque badge pixel =
|
||||
widget color.
|
||||
|
||||
Worked out 2026-08-29 (the recipe was NEVER recorded the first time it was done, so
|
||||
it had to be re-derived from scratch — that's the incident this entry exists to end).
|
||||
|
||||
Reference in New Issue
Block a user