The root cause was a coordinate space mismatch between the floating panel
canvas and the Python backend:
Before (broken):
- Canvas mask window: fixed ~300px (arbitrary, unrelated to actual mask)
- Preview image: drawn at downscaled pixel size (e.g. 768x512)
- offsetX/Y: interpreted in preview image pixel space
- Python output: interprets offsetX/Y in ORIGINAL image pixel space
- Result: 100px offset in preview = 200px in output (2x mismatch at 50% scale)
After (fixed):
- Python sends orig_h/w (original image dims) + bbox_h/w (mask bbox) via mce_info
- Canvas computes zoom-to-fit so the full original image is visible
- Everything rendered in ORIGINAL image pixel space (zoomed for display)
- Mask window size = bbox_w * zoom × bbox_h * zoom (accurate proportional size)
- DrawImage stretches the preview to fill original dimensions (consistent coords)
- Mouse drag sensitivity = 1 / (zoom * scale) for correct image-pixel mapping
- offsetX/Y values in JS == same values applied by Python (no conversion needed)
This ensures WYSIWYG: what you see in the mask window IS what you get in output.