From ebe39efcac610aba6166120e830077c310556ff7 Mon Sep 17 00:00:00 2001 From: baizhi958216 <1475289190@qq.com> Date: Fri, 12 Jun 2026 22:02:32 +0800 Subject: [PATCH] fix(play): stabilize canvas frame during image swaps Signed-off-by: baizhi958216 <1475289190@qq.com> --- components/PlayCanvas.tsx | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/components/PlayCanvas.tsx b/components/PlayCanvas.tsx index 9a03e9f..0235f59 100644 --- a/components/PlayCanvas.tsx +++ b/components/PlayCanvas.tsx @@ -349,10 +349,20 @@ export function PlayCanvas({ // the 9:16 image matches the exact device/window — no letterbox. Landscape // keeps the prior contain-style sizing so the full 16:9 frame stays visible. const sizeStyle: React.CSSProperties = portrait - ? { width: "100vw", height: "100dvh", objectFit: "cover" } + ? { width: "100%", height: "100%", objectFit: "cover" } : fullViewport - ? { maxWidth: "100vw", maxHeight: "100dvh" } - : { maxWidth: "96vw", maxHeight: "calc(100dvh - 200px)" }; + ? { width: "100%", height: "100%", objectFit: "contain" } + : { width: "100%", height: "100%" }; + + const canvasStyle: React.CSSProperties = portrait + ? { width: "100vw", height: "100dvh" } + : { + width: fullViewport + ? "min(100vw, calc(100dvh * 16 / 9))" + : "min(96vw, calc((100dvh - 200px) * 16 / 9))", + aspectRatio: "16 / 9", + maxHeight: fullViewport ? "100dvh" : "calc(100dvh - 200px)", + }; const placeholderStyle: React.CSSProperties = portrait ? { width: "100vw", height: "100dvh" } @@ -382,19 +392,14 @@ export function PlayCanvas({ {imageUrl ? (
- {/* Background image — Runware CDN URL or data URI (mock mode). - The width/height attributes give the browser the intrinsic aspect - ratio (1792:1024 landscape / 1024:1792 portrait) so that, while the - bytes are still arriving from the CDN, the reserves the right - box instead of collapsing to a one-pixel sliver — fixes the - "等很久 → 一根线 → 突然出图" jank. Landscape uses w-auto/h-auto + - maxWidth/maxHeight (contain); portrait switches sizeStyle to - 100vw×100dvh with object-fit:cover (full-bleed, no letterbox). */} + {/* The stable wrapper owns the frame size. Keeping overlay geometry + independent of decode/source swaps prevents controls from + jumping when a newly generated image is committed. */}