fix(play): scene image renders as 1px sliver while CDN bytes still arrive

When the Runware CDN download was slow (~10-20s over VPN / strict
networks, vs. the optimistic <2s the existing comment assumed), the
preload's 8s timeout fired and setImageUrl committed before the bytes
were actually decoded. The rendered <img> has w-auto h-auto and no
intrinsic aspect-ratio source — until the image loads the layout
collapses to roughly 1px tall, giving the "等了很久 → 一根线 → 突然
出图" jank.

Two compounding fixes:

  app/play/page.tsx       IMAGE_PRELOAD_TIMEOUT_MS  8000 → 20000.
                          Real CDN+decode usually finishes well before
                          this; pushing the ceiling out just stops the
                          window where we commit a half-loaded URL.

  components/PlayCanvas.tsx  Add width={1792} height={1024} HTML attrs
                          to the scene <img>. Doesn't affect rendered
                          size (still driven by w-auto h-auto and the
                          maxWidth/maxHeight in sizeStyle); the
                          browser uses them purely as an intrinsic
                          aspect-ratio source, so the placeholder box
                          reserves a 16:9-ish frame even mid-download.

Together: slow networks now mostly wait through preload; on the rare
genuine timeout the layout still holds shape instead of collapsing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
DESKTOP-I1T6TF3\Q
2026-06-03 07:23:28 +08:00
parent ea861b7c99
commit b5f73d8082
2 changed files with 17 additions and 5 deletions
+8 -4
View File
@@ -30,10 +30,14 @@ import type {
const MUTED_STORAGE_KEY = "infiplot:muted";
// Cap how long we wait for the browser to download + decode a scene image
// before giving up and rendering anyway. Runware's CDN is normally <2s for a
// 1792×1024 PNG; tolerate up to 8s before the typewriter starts so a slow
// download can't strand the player on a blank screen forever.
const IMAGE_PRELOAD_TIMEOUT_MS = 8000;
// before giving up and rendering anyway. Runware's CDN is usually <2s for a
// 1792×1024 PNG, but over slow links / VPN / strict corp networks the same
// download can stretch to 10-20s. The previous 8s ceiling fired in that
// window, and because the rendered <img> has no aspect-ratio occupation, the
// layout collapsed to a one-pixel-tall sliver until the bytes actually
// finished arriving — "等了很久 → 一根线 → 突然出图" of the original report.
// 20s + the <img> aspect-video fallback together remove that failure mode.
const IMAGE_PRELOAD_TIMEOUT_MS = 20000;
// ──────────────────────────────────────────────────────────────────────
// Image preload — decode the Runware URL in memory before committing to
+9 -1
View File
@@ -310,11 +310,19 @@ export function PlayCanvas({
className="relative inline-block"
style={{ boxShadow: fullViewport ? "none" : SHADOW }}
>
{/* Background image — Runware CDN URL or data URI (mock mode) */}
{/* Background image — Runware CDN URL or data URI (mock mode).
The width/height attributes are NOT rendered dimensions (w-auto
h-auto + the maxWidth/maxHeight in sizeStyle still drive the
final layout); they give the browser an intrinsic aspect ratio
so that, while the bytes are still arriving from the CDN, the
<img> reserves a 1792:1024 box instead of collapsing to a
one-pixel sliver — fixes the "等很久 → 一根线 → 突然出图" jank. */}
<img
key={imageUrl.slice(-48)}
ref={imgRef}
src={imageUrl}
width={1792}
height={1024}
alt="Generated scene"
onClick={handleImageClick}
draggable={false}