You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat: add pixelPerfect prop to ScrollControls and Html components
Adds pixelPerfect prop to prevent subpixel rendering blur caused by CSS
transform3d values with decimal pixels. Uses devicePixelRatio-based
rounding for accurate rendering across all display types.
Features:
- ScrollControls: pixelPerfect prop for Scroll html components
- Html: pixelPerfect prop for transform mode
- Velocity-based optimization (only applies when motion < 0.001)
- devicePixelRatio support for high-DPI displays
- Comprehensive Storybook examples and documentation
- Performance optimized with conditional application
Credit: chris-xinhai-li for devicePixelRatio suggestion (#2380)
Fixes: #859, #2380
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
Copy file name to clipboardExpand all lines: docs/controls/scroll-controls.mdx
+19-1Lines changed: 19 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -51,12 +51,29 @@ type ScrollControlsProps = {
51
51
style?:React.CSSProperties
52
52
children:React.ReactNode
53
53
}
54
+
55
+
typeScrollProps= {
56
+
/** Rounds transform values to whole pixels to prevent subpixel rendering blur, default false */
57
+
pixelPerfect?:boolean
58
+
/** All other props passed to the scroll container */
59
+
[key:string]:any
60
+
}
54
61
```
55
62
56
63
Scroll controls create an HTML scroll container in front of the canvas. Everything you drop into the `<Scroll>` component will be affected.
57
64
58
65
You can listen and react to scroll with the `useScroll` hook which gives you useful data like the current scroll `offset`, `delta` and functions for range finding: `range`, `curve` and `visible`. The latter functions are especially useful if you want to react to the scroll offset, for instance if you wanted to fade things in and out if they are in or out of view.
59
66
67
+
## PixelPerfect Scrolling
68
+
69
+
When using `<Scrollhtml>` components, you may notice subpixel rendering blur caused by CSS `transform3d` values with decimal pixels. To fix this, use the `pixelPerfect` prop which rounds transform values to whole pixels:
70
+
71
+
```jsx
72
+
<ScrollhtmlpixelPerfect>
73
+
{/* Content will scroll with crisp, pixel-perfect rendering */}
74
+
</Scroll>
75
+
```
76
+
60
77
```jsx
61
78
;<ScrollControlspages={3} damping={0.1}>
62
79
{/* Canvas contents in here will *not* scroll, but receive useScroll! */}
@@ -67,8 +84,9 @@ You can listen and react to scroll with the `useScroll` hook which gives you use
occlude={[ref]} // Can be true or a Ref<Object3D>[], true occludes the entire scene (default: undefined)
42
43
onOcclude={(hidden) =>null} // Callback when the visibility changes (default: undefined)
@@ -111,7 +112,15 @@ Enable shadows using the `castShadow` and `recieveShadow` prop.
111
112
112
113
If transform mode is enabled, the dimensions of the rendered html will depend on the position relative to the camera, the camera fov and the distanceFactor. For example, an Html component placed at (0,0,0) and with a distanceFactor of 10, rendered inside a scene with a perspective camera positioned at (0,0,2.45) and a FOV of 75, will have the same dimensions as a "plain" html element like in [this example](https://codesandbox.io/s/drei-html-magic-number-6mzt6m).
113
114
114
-
A caveat of transform mode is that on some devices and browsers, the rendered html may appear blurry, as discussed in [#859](https://github.com/pmndrs/drei/issues/859). The issue can be at least mitigated by scaling down the Html parent and scaling up the html children:
115
+
A caveat of transform mode is that on some devices and browsers, the rendered html may appear blurry, as discussed in [#859](https://github.com/pmndrs/drei/issues/859). This can be solved using the `pixelPerfect` prop which rounds transform values to whole pixels, ensuring crisp text rendering:
116
+
117
+
```jsx
118
+
<Html transform pixelPerfect>
119
+
<div>Crisp text that won't blur during animations</div>
120
+
</Html>
121
+
```
122
+
123
+
Alternatively, the issue can be mitigated by scaling down the Html parent and scaling up the html children:
0 commit comments