Merge pull request 'fix(web): cap canvas via Window resize_constraints (real surface fix)' (#100) from fix/web-canvas-resize-constraints into master
Build and Deploy / build-and-push (push) Successful in 5m11s
Web E2E / web-e2e (push) Failing after 5m25s
Web WASM Rebuild / rebuild (push) Successful in 6m12s

This commit was merged in pull request #100.
This commit is contained in:
2026-06-24 01:59:36 +00:00
2 changed files with 32 additions and 34 deletions
+18 -33
View File
@@ -6,43 +6,28 @@
<title>Ferrous Solitaire</title>
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
body { background: #000; overflow: hidden; }
/* #bevy-wrap fills the viewport but is capped to the GPU's real
MAX_TEXTURE_SIZE via an inline max-width/height set before init
(see the clamp script below). fit_canvas_to_parent sizes the wgpu
surface to this element, so capping it keeps the surface within
WebGL2's per-dimension limit. Centered so 2048-limited devices
letterbox symmetrically. */
#bevy-wrap {
width: 100vw; height: 100vh; margin: 0 auto;
display: flex; align-items: center; justify-content: center;
html, body { height: 100%; background: #000; overflow: hidden; }
/* Cap the canvas at WebGL2's 2048 max texture dimension (this mirrors
the Window `resize_constraints` in solitaire_web/src/lib.rs — winit
applies that constraint as the canvas's own max-width/max-height).
On wasm Bevy creates the device with downlevel_webgl2_defaults()
whose max_texture_dimension_2d is a fixed 2048, so a larger surface
(e.g. a 4K display at 150% scale → a 2560x1440 logical viewport)
makes Surface::configure panic. `max-*` directly on the canvas keeps
the surface ≤ 2048 regardless of how fit_canvas_to_parent resolves
its 100% width; `margin: 0 auto` centres the letterbox horizontally. */
#bevy-canvas {
display: block;
width: 100%;
height: 100%;
max-width: 2048px;
max-height: 2048px;
margin: 0 auto;
}
#bevy-canvas { display: block; width: 100%; height: 100%; }
</style>
</head>
<body>
<div id="bevy-wrap"><canvas id="bevy-canvas"></canvas></div>
<script>
// Clamp the Bevy canvas's backing buffer to 2048px *before* the wasm
// initialises. `fit_canvas_to_parent` sizes the wgpu surface to
// #bevy-wrap, and on wasm Bevy creates the device with
// `Limits::downlevel_webgl2_defaults()` (forced by
// `WgpuSettingsPriority::WebGL2` in solitaire_web/src/lib.rs), whose
// `max_texture_dimension_2d` is a fixed **2048** — independent of the
// GPU's real MAX_TEXTURE_SIZE (which is why querying the hardware limit
// doesn't help: a 4K/integrated GPU reports e.g. 8192 but wgpu still
// caps the surface at 2048). A surface wider/taller than 2048 makes
// Surface::configure panic and kill the WASM thread on the first frame
// — e.g. a 3840x2160 display at 150% scale gives a 2560x1440 logical
// viewport → a 2560-wide surface. So the cap is the constant 2048.
// Keep in sync with the wgpu limit selected in lib.rs.
(function clampCanvasToWebgl2Limit() {
var MAX = 2048; // wgpu downlevel_webgl2_defaults().max_texture_dimension_2d
var wrap = document.getElementById("bevy-wrap");
wrap.style.maxWidth = MAX + "px";
wrap.style.maxHeight = MAX + "px";
})();
</script>
<canvas id="bevy-canvas"></canvas>
<script type="module">
import init from "/web/pkg/canvas.js";
// solitaire_wasm.js provides SolitaireGame with the full debug / automation
+14 -1
View File
@@ -13,7 +13,7 @@ use bevy::asset::AssetMetaCheck;
use bevy::prelude::*;
use bevy::render::RenderPlugin;
use bevy::render::settings::{RenderCreation, WgpuSettings, WgpuSettingsPriority};
use bevy::window::{Window, WindowPlugin, WindowResolution};
use bevy::window::{Window, WindowPlugin, WindowResizeConstraints, WindowResolution};
use solitaire_data::LocalOnlyProvider;
use solitaire_engine::CoreGamePlugin;
use wasm_bindgen::prelude::*;
@@ -42,6 +42,19 @@ pub fn start() {
// resize event and killing the WASM thread.
resolution: WindowResolution::default()
.with_scale_factor_override(1.0),
// Cap the surface at WebGL2's max texture dimension (2048).
// On wasm Bevy creates the device with
// `Limits::downlevel_webgl2_defaults()` (max_texture_dimension_2d
// = 2048), so a larger surface — e.g. a 4K display at 150% scale
// gives a 2560x1440 logical viewport — makes Surface::configure
// panic on the first frame. winit maps this constraint to the
// canvas's `max-width`/`max-height` style, so the surface can
// never exceed it. Viewports wider/taller than 2048 letterbox.
resize_constraints: WindowResizeConstraints {
max_width: 2048.0,
max_height: 2048.0,
..default()
},
..default()
}),
..default()