fn framed_transform(zoom: ZoomTransform, crop: CropRect) -> TransformExpand description
Build the screen-sprite transform that applies crop then zoom.
The base screen sprite maps a normalized source point (u, v) to NDC
(2u − 1, −(2v − 1)) (centre-anchored, scale 2; the − on v is wisp’s
+y-up convention — the decoded top-down frame is flipped bottom-up at
upload). This composes two affines into the single transform the sprite
carries:
- Crop
[x, y, w, h]→ fill the sub-rect: scale2/w, 2/hand recentre so the crop centre lands at NDC(0, 0). - Zoom by
zabout the focal NDC point(2·fx − 1, −(2·fy − 1)), keeping that point fixed:pos += focal · (1 − z).
Composed zoom ∘ crop: scale = z · crop_scale,
pos = z · crop_pos + zoom_pos. Pure — no GPU, exhaustively testable.