Markdown images without dim are upscaled to the fallback reserve box on first view (badges render huge)
- Dominant language
- Rust
- Stars
- 32.7k
- Forks
- 4.3k
- Avg merge
- 1d 13h
- Merged PRs (30d)
- 253
Description
## 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.:
```markdown

```
**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.
Contributor guide
Research direction
Start in desktop/src/shared/ui/markdown/utils.ts with resolveImageReserveBox and useFrozenImageReserve, then inspect IMAGE_CLASS and image loading in desktop/src/shared/ui/markdown/ProgressiveImage.tsx. Reproduce the first and subsequent views with the shields.io badge; done means dim-less small images render at intrinsic size on first view without regressing large-image reserve behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- desktop, frontend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 68/100