Skip to content

fix(core): round thumbnail dimensions to prevent sub-pixel gaps#995

Merged
mihar-22 merged 1 commit intomainfrom
fix/thumbnail-dimensions
Mar 19, 2026
Merged

fix(core): round thumbnail dimensions to prevent sub-pixel gaps#995
mihar-22 merged 1 commit intomainfrom
fix/thumbnail-dimensions

Conversation

@sampotts
Copy link
Copy Markdown
Collaborator

@sampotts sampotts commented Mar 18, 2026

Closes #996

Summary

Round thumbnail dimensions to integers in ThumbnailCore.resize() to prevent sub-pixel rendering gaps in Chrome.

Changes

  • Wrap all dimension outputs (containerWidth, containerHeight, imageWidth, imageHeight, offsetX, offsetY) with Math.round() in ThumbnailCore.resize()
  • Add test verifying fractional scales produce integer pixel values
Implementation details

ThumbnailCore.resize() multiplies tile dimensions by a float scale factor (e.g. tileHeight * scale). These fractional pixel values get written directly to the DOM as inline styles. When Chrome renders an element at a fractional pixel boundary (e.g. 110.625px), it anti-aliases the edge, producing a visible light line at the bottom of the thumbnail.

The default skin already has overflow: clip on .media-preview__thumbnail, but that only clips overflowing content — it doesn't fix the anti-aliased edge of the element's own box at a sub-pixel boundary.

Rounding at the source fixes all skins and consumers in one place. The ±0.5px difference is visually imperceptible while eliminating the rendering artifact.

Testing

pnpm -F @videojs/core test src/core/ui/thumbnail/tests/thumbnail-core.test.ts

Copilot AI review requested due to automatic review settings March 18, 2026 03:29
@netlify
Copy link
Copy Markdown

netlify bot commented Mar 18, 2026

Deploy Preview for vjs10-site ready!

Name Link
🔨 Latest commit b93fae4
🔍 Latest deploy log https://app.netlify.com/projects/vjs10-site/deploys/69bbb17721cf8e0008b8fb9b
😎 Deploy Preview https://deploy-preview-995--vjs10-site.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@vercel
Copy link
Copy Markdown

vercel bot commented Mar 18, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
v10-sandbox Ready Ready Preview, Comment Mar 19, 2026 8:19am

Request Review

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 18, 2026

📦 Bundle Size Report

🎨 @videojs/html — no changes
Presets (7)
Entry Size
/video (default) 23.19 kB
/video (default + hls) 153.71 kB
/video (minimal) 23.06 kB
/video (minimal + hls) 153.59 kB
/audio (default) 21.48 kB
/audio (minimal) 21.43 kB
/background 6.38 kB
Media (5)
Entry Size
/media/background-video 1.03 kB
/media/container 1.59 kB
/media/dash-video 236.04 kB
/media/hls-video 131.57 kB
/media/simple-hls-video 12.33 kB
Players (3)
Entry Size
/video/player 6.24 kB
/audio/player 6.23 kB
/background/player 6.22 kB
Skins (16)
Entry Type Size
/video/minimal-skin.css css 3.12 kB
/video/skin.css css 3.15 kB
/video/minimal-skin js 22.25 kB
/video/minimal-skin.tailwind js 22.49 kB
/video/skin js 22.42 kB
/video/skin.tailwind js 22.73 kB
/audio/minimal-skin.css css 2.28 kB
/audio/skin.css css 2.30 kB
/audio/minimal-skin js 20.66 kB
/audio/minimal-skin.tailwind js 20.69 kB
/audio/skin js 20.66 kB
/audio/skin.tailwind js 20.93 kB
/background/skin.css css 117 B
/background/skin js 1003 B
/base.css css 157 B
/shared.css css 86 B
UI Components (21)
Entry Size
/ui/alert-dialog 2.08 kB
/ui/alert-dialog-close 1.63 kB
/ui/alert-dialog-description 1.52 kB
/ui/alert-dialog-title 1.55 kB
/ui/buffering-indicator 1.78 kB
/ui/captions-button 1.79 kB
/ui/controls 1.59 kB
/ui/fullscreen-button 1.81 kB
/ui/mute-button 1.78 kB
/ui/pip-button 1.80 kB
/ui/play-button 1.82 kB
/ui/playback-rate-button 1.81 kB
/ui/popover 3.27 kB
/ui/poster 1.75 kB
/ui/seek-button 1.80 kB
/ui/slider 2.02 kB
/ui/thumbnail 2.12 kB
/ui/time 1.68 kB
/ui/time-slider 2.12 kB
/ui/tooltip 2.40 kB
/ui/volume-slider 2.26 kB

Sizes are marginal over the root entry point.

⚛️ @videojs/react — no changes
Presets (7)
Entry Size
/video (default) 19.00 kB
/video (default + hls) 149.82 kB
/video (minimal) 19.03 kB
/video (minimal + hls) 149.71 kB
/audio (default) 14.93 kB
/audio (minimal) 15.05 kB
/background 3.13 kB
Media (4)
Entry Size
/media/background-video 476 B
/media/dash-video 236.19 kB
/media/hls-video 131.59 kB
/media/simple-hls-video 12.34 kB
Skins (14)
Entry Type Size
/video/minimal-skin.css css 3.12 kB
/video/skin.css css 3.15 kB
/video/minimal-skin js 18.93 kB
/video/minimal-skin.tailwind js 22.13 kB
/video/skin js 18.95 kB
/video/skin.tailwind js 22.14 kB
/audio/minimal-skin.css css 2.28 kB
/audio/skin.css css 2.30 kB
/audio/minimal-skin js 14.94 kB
/audio/minimal-skin.tailwind js 17.02 kB
/audio/skin js 14.88 kB
/audio/skin.tailwind js 17.25 kB
/background/skin.css css 90 B
/background/skin js 272 B
UI Components (18)
Entry Size
/ui/alert-dialog 2.24 kB
/ui/buffering-indicator 2.21 kB
/ui/captions-button 2.25 kB
/ui/controls 2.24 kB
/ui/fullscreen-button 2.27 kB
/ui/mute-button 2.26 kB
/ui/pip-button 2.27 kB
/ui/play-button 2.24 kB
/ui/playback-rate-button 2.27 kB
/ui/popover 2.87 kB
/ui/poster 2.08 kB
/ui/seek-button 2.27 kB
/ui/slider 3.17 kB
/ui/thumbnail 2.01 kB
/ui/time 1.93 kB
/ui/time-slider 2.65 kB
/ui/tooltip 2.69 kB
/ui/volume-slider 2.68 kB

Sizes are marginal over the root entry point.

🧩 @videojs/core — no changes
Entries (6)
Entry Size
. 4.81 kB
/dom 8.41 kB
/dom/media/custom-media-element 1.81 kB
/dom/media/dash 235.62 kB
/dom/media/hls 131.27 kB
/dom/media/simple-hls 11.85 kB
🏷️ @videojs/element — no changes
Entries (2)
Entry Size
. 999 B
/context 943 B
📦 @videojs/store — no changes
Entries (3)
Entry Size
. 1.32 kB
/html 700 B
/react 360 B
🔧 @videojs/utils — no changes
Entries (10)
Entry Size
/array 104 B
/dom 1.25 kB
/events 227 B
/function 261 B
/object 119 B
/predicate 265 B
/string 148 B
/style 190 B
/time 478 B
/number 158 B
📦 @videojs/spf — no changes
Entries (3)
Entry Size
. 40 B
/dom 10.04 kB
/playback-engine 9.94 kB

ℹ️ How to interpret

All sizes are standalone totals (minified + brotli).

Icon Meaning
No change
🔺 Increased ≤ 10%
🔴 Increased > 10%
🔽 Decreased
🆕 New (no baseline)

Run pnpm size locally to check current sizes.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adjusts thumbnail sizing in ThumbnailCore.resize() to avoid sub-pixel container dimensions that can render as visible “white lines” around/inside the clipped thumbnail container.

Changes:

  • Round down computed containerWidth and containerHeight via Math.floor(...) in ThumbnailCore.resize().

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment thread packages/core/src/core/ui/thumbnail/thumbnail-core.ts Outdated
Comment thread packages/core/src/core/ui/thumbnail/thumbnail-core.ts Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aims to eliminate sub-pixel thumbnail container sizing that can produce visible 1px “white line” artifacts by rounding the computed container dimensions down to whole pixels.

Changes:

  • Round containerWidth and containerHeight down using Math.floor() in ThumbnailCore.resize() to avoid fractional pixel container sizes.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment thread packages/core/src/core/ui/thumbnail/thumbnail-core.ts Outdated
Comment thread packages/core/src/core/ui/thumbnail/thumbnail-core.ts Outdated
@sampotts sampotts force-pushed the fix/thumbnail-dimensions branch from 6cf8b6d to f5530d6 Compare March 18, 2026 04:30
@sampotts sampotts changed the title fix(core): round down container size for thumbnails fix(core): round container size for thumbnails Mar 18, 2026
@sampotts sampotts force-pushed the fix/thumbnail-dimensions branch from f5530d6 to 3f4d449 Compare March 18, 2026 04:55
@sampotts sampotts changed the title fix(core): round container size for thumbnails fix(core): round down container size for thumbnails Mar 18, 2026
@sampotts sampotts requested a review from Copilot March 18, 2026 04:55
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses a UI rendering artifact where fractional-pixel thumbnail container dimensions can produce thin white lines (notably in Chrome), by rounding computed container dimensions down to integer pixels.

Changes:

  • Add a helper to floor scaled container dimensions (with a small epsilon to avoid floating-point noise).
  • Apply the rounding helper to containerWidth/containerHeight in ThumbnailCore.resize().
  • Add unit tests covering fractional container sizes, scale-up rounding behavior, and float-noise handling.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
packages/core/src/core/ui/thumbnail/thumbnail-core.ts Floors scaled container dimensions to integers to prevent fractional-pixel border artifacts.
packages/core/src/core/ui/thumbnail/tests/thumbnail-core.test.ts Adds tests validating the new rounding behavior in several scenarios.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment thread packages/core/src/core/ui/thumbnail/thumbnail-core.ts Outdated
Comment thread packages/core/src/core/ui/thumbnail/tests/thumbnail-core.test.ts Outdated
@mihar-22
Copy link
Copy Markdown
Member

I'll need to validate a few things work as expected on my end with scaling. Can you provide the thumbnail source so I can test?

@sampotts
Copy link
Copy Markdown
Collaborator Author

sampotts commented Mar 18, 2026

I'll need to validate a few things work as expected on my end with scaling. Can you provide the thumbnail source so I can test?

Sure, you can use the sandbox since I've setup the storyboards there. Here's how it is currently (check it out on Chrome or something Chromium based to see the bug):
https://v10-sandbox.vercel.app/?platform=html&styling=css&preset=video&skin=default&source=hls-4

and with the fix:
https://v10-sandbox-git-fix-thumbnail-dimensions-mux.vercel.app/?platform=html&styling=css&preset=video&skin=default&source=hls-4

Feel free to close this PR and do it another way, we just shouldn't be setting fractional pixel dimensions.

@mihar-22 mihar-22 force-pushed the fix/thumbnail-dimensions branch from 3f4d449 to b93fae4 Compare March 19, 2026 08:19
@mihar-22 mihar-22 changed the title fix(core): round down container size for thumbnails fix(core): round thumbnail dimensions to prevent sub-pixel gaps Mar 19, 2026
@mihar-22 mihar-22 merged commit 636ccd4 into main Mar 19, 2026
20 checks passed
@mihar-22 mihar-22 deleted the fix/thumbnail-dimensions branch March 19, 2026 08:21
@luwes luwes mentioned this pull request Mar 19, 2026
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.

Skins: Thumbnails show white line at bottom

3 participants