Skip to content

feat(instagram): auto-fit story images to 9:16 with blurred background#123

Draft
paulocastellano wants to merge 2 commits into
mainfrom
feat/story-blurred-background
Draft

feat(instagram): auto-fit story images to 9:16 with blurred background#123
paulocastellano wants to merge 2 commits into
mainfrom
feat/story-blurred-background

Conversation

@paulocastellano

@paulocastellano paulocastellano commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Problem

A customer reported that Instagram story images that aren't 9:16 get clipped — the platform crops anything that doesn't fill the 9:16 frame. While fixing it, the same cropping showed up in the editor's vertical previews (stories, reels, TikTok, Shorts).

Publish-time fit (Instagram story)

Story images are now fitted onto a 1080×1920 canvas at publish time: the original is contained (never cropped) and a blurred, slightly darkened copy of itself fills the gaps. The background color adapts from the image — no color choice to make.

  • MediaOptimizer::fitToCanvas() — the blurred-background fit (no-op when the ratio already matches; two image decodes, not three).
  • CropsImageForAspectRatio::fitImageToCanvas() — downloads the source, fits it, hosts the derivative under social-crops/ (mirrors the existing crop helper), so publishing never depends on an external URL.
  • InstagramPublisher::publishStory() — image stories post the hosted, fitted copy.

Instagram only — Facebook stories are video-only in our flow.

Editor previews (all vertical formats)

The vertical previews rendered media full-bleed, so a correctly-sized 9:16 image was clipped by the phone mockup (which is taller than 9:16). A shared VerticalMediaCanvas now renders every vertical format consistently:

  • Image → shown in full with a blurred-background extension filling the gaps. No crop.
  • Video → full-bleed, like the real feed.

Used by IG Story, IG Reel, FB Story, FB Reel, TikTok and YouTube Short. This mirrors how the platforms display the content and matches the publish-time story blur. The aspect-ratio warning is also suppressed for story images (autoFitsImage), since they're auto-fitted.

Tests

  • MediaOptimizerTest — wide image → 9:16 fit; no letterbox when the ratio already matches.
  • Instagram story tests (both publisher files) assert the hosted social-crops/ copy is posted, not the raw external URL.

Full suite: 2347 passed, 2 skipped. Frontend eslint clean.

Story images that aren't 9:16 were clipped by Instagram. They are now
fitted onto a 1080x1920 canvas — the image is contained and a blurred,
darkened copy of itself fills the letterbox gaps, so nothing is cropped
and the background color adapts to the image.

The fit happens at publish time (the hosted copy lives in social-crops/),
and the post editor preview now renders the same blurred-background fit
for stories, so the user sees exactly what will publish. The aspect-ratio
warning is suppressed for story images since they're auto-fitted.

Instagram only — Facebook stories are video-only in our flow.
Vertical previews (stories, reels, TikTok, Shorts) rendered media full-bleed,
so a correctly-sized 9:16 image was clipped by the phone mockup, which is
taller than 9:16.

A shared VerticalMediaCanvas now renders every vertical format consistently:
images show in full with a blurred-background extension filling the gaps (no
crop), while videos stay full-bleed like the real feed. This mirrors how the
platforms themselves display the content and matches the story blur applied at
publish time.

Also reduce fitToCanvas to two image decodes instead of three (reuse the probe
as the foreground), lowering peak memory on the story publish path.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant