Window
The UI viewport's size reaches React through two built-ins: the resize
event and the bevy.window.size()
request, the bevy-react counterparts
of the browser's resize event and window.innerWidth/innerHeight. Both
are typed in every generated bevy.ts, with no Rust code or registration.
Usage
Seed the value with the request on mount, then follow the event:
import { useEffect, useState } from "react";
import { bevy, type WindowSize } from "./bevy"; // generated
function useWindowSize(): WindowSize | null {
const [size, setSize] = useState<WindowSize | null>(null);
useEffect(() => {
bevy.window.size().then(setSize, () => {});
return bevy.on("resize", setSize);
}, []);
return size;
}What is measured
Both report a WindowSize, { width, height }, in logical pixels: the same
unit as plain numbers in styles.
- The size is the viewport of the default UI camera, the camera
bevy_uilays the UI out against (the one markedIsDefaultUiCamera). It stays correct when that camera renders to a viewport or an offscreen texture. - Without a camera marked
IsDefaultUiCamera, the size of the app's window is used. With several windows and no such camera, there is no size. - Logical pixels depend on the display's scale factor, so moving the window to a display with another scale factor changes the size too.
The resize event
- The first
resizeis sent once React's first render has been applied to the world, so listeners subscribed in the effects of your initial tree receive the starting size. - After that, one
resizeis sent per frame in which the size changed, and never for an unchanged size. A window being dragged larger sends one per frame. - A component that mounts later has missed the earlier events: call the request on mount, as in the usage example. The answer and the events travel in one ordered channel, so the newest value always lands last.
The size request
bevy.window.size() resolves with the current size at any time. It rejects
with no UI viewport available when there is no viewport to measure, such as
before a window exists or in a headless app, so always pass a rejection
handler.
Responsive layout
Sizes that only depend on the viewport need no events: the vw, vh,
vmin and vmax units re-resolve on every resize without a React render
(see Units). Read the size when the tree itself has to
change, such as a compact layout under a breakpoint:
function Shell() {
const size = useWindowSize();
if (!size) return null; // nothing until the size is known
return size.width < 720 ? <CompactShell /> : <WideShell />;
}Rendering nothing until the first size arrives avoids a first frame in the
wrong layout. Each resize re-renders every subscribed component, so keep
the subscription near the top and pass the derived value down, or share it
through a React context.
Limits
- Only the size is reported: no window position, focus, or scale factor.
- In a multi-window app, mark the UI camera with
IsDefaultUiCamera, or no size is reported. - A
<canvas>'s ownonResizereports that element's size, not the viewport's.
The built-in types are listed in the generated
bevy.ts reference.
bevy-react