Responsive Canvas

Hi guys,

I know this question was asked a few times now, but it seems some of the guides available online are basic or out of date. Or there is just a few way to do the sam thing.

Question 1:
Is there a better way to make Three.js canvas respond to window / container size change? Seems too long too me

// GLOBAL VARIABLES
const containerElement = document.querySelector('#scene-container')

// CANVAS
const canvasSizes = {
    width: containerElement.clientWidth,
    height: containerElement.clientHeight
}

// Resize event
window.addEventListener('resize', () => {
    // Update sizes
    canvasSizes.width = containerElement.clientWidth
    canvasSizes.height = containerElement.clientHeight

    // Update camera
    camera.aspect = canvasSizes.width / canvasSizes.height
    camera.updateProjectionMatrix()

    // Update render
    renderer.setSize(canvasSizes.width, canvasSizes.height)
    renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
})

Question 2:
While the solution works I have a problem. When resizing window quickly div block resize speed is lugging behind?

body {
    /* Remove margins and scroll bars */
    margin: 0;
    overflow: hidden;
    background-color: coral;
}

#scene-container {
    display: block;
    margin: 30px;
    height: calc(100dvh - 60px);
    border-radius: 30px;
    background-color: blueviolet;
    outline: none;
    box-shadow: 0px 0px 30px 0px rgb(0 0 0 / 0.2);
    overflow: hidden;
}
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Three.js Basics</title>
    <link href="./style.css" rel="stylesheet" type="text/css">
    <script type="module" src="./main.js"></script>
</head>

<body>
    <div id="scene-container">
        <!-- Place for Three.js <canvas> -->
    </div>
</body>

</html>

Here is a video:

Thank you

First idea:

Is this necessary on resize? (i guess maybe if DPR changed in the course of the resize, but does that happen?)

second idea:
Your resize handler looks pretty standard… but of course, you won’t see an updated canvas until your renderer gets a chance to render…

You might squeak a little more “responsiveness” by adding a renderer.render( scene, camera) right at the end of your resize handler… haven’t tried that before… but it might cause some bog when doing fast resizing, or create excess GPU pressure by calling it outside the RAF.

third idea:
you don’t HAVE to resize the renderer on resize… resizing the canvas will usually also just scale the contents, so perhaps you could “debounce” resize by only doing renderer.resize() after you set a “needsResize” flag in your code on the resize handler.

So that you only call renderer.resize inside your animation loop… right before the render, and only when your needsResize flag is set… or even… at some fixed interval like 10 fps, and rely on the browsers default canvas resize behavior to at least “scale” the existing canvas contents during high frequency resize… and then only update the canvas resolution periodically.

fourth idea:

what browser are you using? If it’s not chrome… then you’re kinda at the mercy of whatever janky browser yr on.

final thought:
I set canvas css to width/height = 100%
with the bog standard resize handler, and it seems to be pretty solid.
Do you have the canvas css width/height set to 100% ?
I tried the different “ideas” i proposed, and honestly don’t see much difference in the behavior. So IDK, YMMV

https://hip-thirsty-chef.glitch.me/

Thank you,
Regarding browser:
I have the same problem in Chrome as well.
Not sure I need width / height 100% as it does nothing until it has canvas with set size.
I am using:

margin: 30px;
height: calc(100dvh - 60px);

And I am not using window sizing I am using container element size. Because the container could have smaller size than window. So I am taking actual div sizes.

On rare occasions when a user reflows views, the threads react FUBAR. One may expose a normalized performance delta or… Autonomous, discrete stdout max. Unified component state in the scene graph is what responsive web design is all about! For example, you can hook degraded paints and combine with visibility observers or fallback snapshots. Also, you don’t need to calculate aspect every frame if you’re on mobile. Cache the props of orientation, keyboard and gimbal.

Edit 0: if global stylesheet uses transition/delay it may google stretchup.