Skip to content

Markdown images without dim are upscaled to the fallback reserve box on first view (badges render huge) #4384

Description

@tinybluedev

Summary

Small markdown images (badges, icons) are upscaled to fill the fallback reserve box on first view, rendering a ~20px shields-style badge as a huge blurry block. The same image renders at its correct natural size on the second view, because the decoded size cache then supplies real dimensions. The bug is the inconsistency between first view and every subsequent view.

Environment

  • Buzz Desktop 0.5.3 (macOS, Apple Silicon), also reproduced on 0.5.2
  • Any channel, plain markdown message

Repro

Post a message containing a small dim-less image, e.g.:

![](https://img.shields.io/badge/OPEN-b91c1c.svg?style=flat-square)

Expected: the badge renders at its intrinsic size (roughly 46x20).

Actual: it renders as a giant block filling a ~384x256 area, visibly upscaled. After the decoded size has been cached (e.g. remount of the message list), the same message renders the badge at its natural size.

Related symptoms from the same mechanism:

  • A wide image (e.g. 1200x240) is scaled down into the same box, making its text unreadably small.
  • Small raster images are upscaled and pixelated.

Root cause (from reading main)

desktop/src/shared/ui/markdown/utils.ts:

  • A dim-less image with no cached decode gets DEFAULT_IMAGE_RESERVE = { height: 256, width: 384 } and useFixedReserveBox: true (resolveImageReserveBox).
  • useFrozenImageReserve deliberately freezes that box for the lifetime of the mount (sound layout-shift reasoning).

desktop/src/shared/ui/markdown/ProgressiveImage.tsx:

  • IMAGE_CLASS uses object-contain inside the frame. object-contain scales UP as well as down, so a 46x20 badge is stretched to fill the 384x256 frame for the entire first view.

rememberDecodedImageDimensions caches the natural size on load, which is why the second view is correct — the first view never benefits from the decode that happens inside it.

Suggested fix

Either of these preserves the layout-shift guarantee for large images:

  1. When a dim-less image decodes and its natural size fits entirely inside the reserve box, adopt the natural size immediately (collapse the frame). First view then matches the cached second-view behavior the code already intends. Shift is shrink-only and only for small images.
  2. Alternatively/minimally: object-scale-down instead of object-contain on the inline image, so small images never upscale (they would sit centered in the reserve box until decode-cache kicks in on later views).

Happy to open a PR for option 1 if the direction is acceptable.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions