refactor(rhi-webgl): rework canvas resolution API, follow display size by default#3037
refactor(rhi-webgl): rework canvas resolution API, follow display size by default#3037luo2430 wants to merge 43 commits into
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
Walkthrough
ChangesOffscreenCanvas detection and auto-resize
Sequence Diagram(s)sequenceDiagram
participant Caller
participant WebGLEngine
participant ResizeObserver
participant WebCanvas
Caller->>WebGLEngine: enableAutoResize(pixelRatio?)
WebGLEngine->>ResizeObserver: disconnect() (prior observer, if any)
WebGLEngine->>ResizeObserver: new ResizeObserver(callback)
WebGLEngine->>ResizeObserver: observe(canvas element)
WebGLEngine->>WebGLEngine: on(Shutdown, _cleanupResizeObserver)
Note over ResizeObserver,WebCanvas: canvas client dimensions change
ResizeObserver->>WebCanvas: resizeByClientSize(pixelRatio)
Caller->>WebGLEngine: disableAutoResize()
WebGLEngine->>WebGLEngine: off(Shutdown, _cleanupResizeObserver)
WebGLEngine->>ResizeObserver: disconnect()
Note over WebGLEngine: engine.destroy() triggers Shutdown
WebGLEngine->>WebGLEngine: _cleanupResizeObserver()
WebGLEngine->>ResizeObserver: disconnect()
Estimated code review effort🎯 2 (Simple) | ⏱️ ~15 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@tests/src/rhi-webgl/WebGLEngine.test.ts`:
- Around line 140-145: The spy on the _cleanupResizeObserver method is created
after enableAutoResize() has already registered the Shutdown listener, meaning
the listener holds a reference to the original function rather than the spied
version. Move the vi.spyOn call for cleanupResizeObserverSpy to before the
enableAutoResize() call to ensure the registered Shutdown listener captures the
spied function reference, allowing the assertion on
cleanupResizeObserverSpy.toHaveBeenCalledTimes(1) to work correctly.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: ca7819a5-d724-46f3-ad7d-879ae0800382
📒 Files selected for processing (3)
packages/core/src/input/InputManager.tspackages/rhi-webgl/src/WebGLEngine.tstests/src/rhi-webgl/WebGLEngine.test.ts
|
这里有一个时序问题需要提一下,根据 W3C 规范,浏览器每帧的渲染管线顺序是: 在发生 resize 那帧,引擎绘制 rAF 时使用的还是旧的画布尺寸,随后 ResizeObserver 回调修改画布的尺寸会清空 canvas buffer ,表现就是这一帧会白,但 window 监听 resize 也不可以直接用,因为 window.resize 仅监听浏览器窗口大小变化,所以其他引擎要么完全手动触发,要么轮询检测,避免本帧 resize 与渲染不同步。 |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## dev/2.0 #3037 +/- ##
===========================================
+ Coverage 79.37% 79.58% +0.20%
===========================================
Files 903 904 +1
Lines 100632 101224 +592
Branches 11260 11404 +144
===========================================
+ Hits 79879 80558 +679
+ Misses 20569 20482 -87
Partials 184 184
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
代码处理完毕,vitest问题我会去开一个issue,有部分解决方案和提议,但需要验证。另外,isOffscreenCanvas中的 |
|
@cptbtptpbcptdtptp 这里有好康的 |
|
|
@cptbtptpbcptdtptp 这个示例能分享一下吗?我用于测试。 |
examples/src/device-restore.ts 这个,设置 enableAutoResize 就可以。 |
@GuoLei1990 我根据pr改动修改了文档,需要commit在这吗? |
|
嗯嗯,可以的,是我遗漏了!PR 拉到最新帮忙适配下吧🙏 |
- Updated canvas resizing logic in docs from resizeByClientSize to setAutoResolution and setResolution - Aligned English and Chinese documentation for physics and platform modules - Removed deprecated method calls from README and example snippets - Enhanced clarity on device pixel ratio (DPR) handling and resolution strategies
@GuoLei1990 提交了,但严格来说要设置lint-staged的,不然直接提交报错 |
👌 |
|
@cptbtptpbcptdtptp 帮忙审阅一下 |
cptbtptpbcptdtptp
left a comment
There was a problem hiding this comment.
整体方向认可:auto-resize 归位 WebCanvas、pump 下沉基类、width/height 只读 + setResolution 原子入口,归属和 API 形态都比旧的清晰。残留清理也很干净(全仓已无 resizeByClientSize / canvas.width = 写入残留),_exitAutoResize 清 pending 的竞态处理、Shutdown 释放时序都是对的。
但默认开启的 auto 路径上有 1 个 blocker(行内 ①)和 2 个兼容性缺口(行内 ②③),建议修复 ① 后再合入。
行内评论索引(① 最重要):
| # | 位置 | 问题 | 验证方式 |
|---|---|---|---|
| ① | WebCanvas.ts L95 | canvas 无 CSS 尺寸时 auto-resize 布局反馈环,分辨率指数发散至白屏 | Chromium 实测复现 |
| ② | WebCanvas.ts L58 | new ResizeObserver 无特性检测,小程序 adapter 无此 polyfill,create() 直接崩 |
adapter 仓库全文检索 |
| ③ | WebCanvas.ts L64 | 默认 content-box 观察,DPR-only 变化(跨屏拖动/zoom)不触发更新 | 规范推导,建议真机验证 |
| ④ | Canvas.ts L35 | setResolution 非整数时引擎缓存与真实 buffer 分叉 |
Chromium 实测 |
| ⑤ | Canvas.ts L62 | 新增 _ 成员缺 /** @internal */,会泄漏进公开 d.ts |
tsconfig stripInternal: true |
| ⑥ | WebCanvas.ts L49 | OffscreenCanvas 上显式调 setAutoResolution 静默丢弃 |
代码事实 |
其余较轻的点,集中列在这里:
- e2e 语义变化:31 处
resizeByClientSize(2)→setAutoResolution(2)不等价——前者固定 ×2 与 DPR 无关,后者 ×DPR×2。CI 的 DPR=1 时结果相同,但本地 Retina 跑 e2e 会与 baseline 环境分叉。e2e 要的是确定性,建议改用setResolution锁定分辨率。 - 单测截图 baseline:7 张 png 更新是 create 默认 auto 使 canvas 分辨率跟随 playwright 页面布局所致,可解释;但 baseline 从此绑定 vitest browser 的默认 viewport,建议在 PR 描述注明。
- create 失败路径泄漏:
_initializereject 时不会走 Shutdown,已创建的 ResizeObserver 泄漏。可在 create 的失败分支里调webCanvas._destroy()。 - README quickstart:
packages/galacean/README.md示例的 canvas 无任何 CSS 尺寸,配合默认 auto 正好落进 ① 的触发条件,修 ① 时记得同步补样式或说明。 - 无关改动混入:e2e/examples 的 prettier 重排、
animator?.play顺手加 optional chaining、vitest.config.ts的screenshotFailures: false与主题无关,建议在描述里说明缘由或剥离。
验证方法说明:①④ 是在 Chromium 中 1:1 复刻本 PR WebCanvas 的 setAutoResolution/_pumpPendingResize 逻辑实测复现(数据见行内评论);② 是对 galacean/platform-adapter 仓库的全文检索;③ 是 ResizeObserver 规范行为推导——顺带提醒:headless/CDP 的 deviceScaleFactor 模拟对 devicePixelContentBoxSize 不生效(window.devicePixelRatio 显示 2 但 dpcb 仍按真实 DPR 返回),所以 ①③ 这类问题 headless 环境测不出来,与 PR 描述"建议真机验一次"的判断一致,真机务必验。
| } | ||
|
|
||
| // OffscreenCanvas has no display size to follow | ||
| if (this._isOffscreenCanvas()) return; |
There was a problem hiding this comment.
[P3] OffscreenCanvas 上显式调用被静默丢弃
create 默认调用时静默跳过合理;但用户对 OffscreenCanvas 引擎显式调 setAutoResolution(0.7) 期待生效,现状连 scale 都直接丢弃且无任何反馈。建议 console.warn 一次,或至少在 JSDoc/docs 标注"OffscreenCanvas 仅支持 setResolution"。
|
@cptbtptpbcptdtptp 先简单加了internal,另外 |
这个结果符合预期——两种 box 在窗口/布局尺寸变化时行为完全一致,常规 resize 测试看不出差异。差异只出现在 devicePixelRatio 变了、但 CSS 尺寸没变的场景,典型两个:把窗口拖到不同缩放比例的显示器;对固定 px 尺寸的 canvas 做浏览器缩放(Ctrl +/-)。 另外注意:如果测试页的 canvas 是 60 秒复现(任意页面 DevTools console 粘贴,然后 Ctrl+加号 缩放几次): const c = document.createElement("canvas");
c.style.cssText = "width:200px;height:100px"; // 固定 CSS px,隔离 DPR-only 变化
document.body.append(c);
new ResizeObserver(() => console.log("content-box fired, dpr =", devicePixelRatio)).observe(c);
const ro = new ResizeObserver((es) => {
const b = es[0].devicePixelContentBoxSize[0];
console.log("device-pixel-content-box fired:", b.inlineSize + "x" + b.blockSize, "dpr =", devicePixelRatio);
});
ro.observe(c, { box: "device-pixel-content-box" });预期:每次缩放只有 两个小点顺带:
|
等会儿验证 |
…llback for ResizeObserver
edge验证有效,之前无效是因为开启了设备仿真模式 |
…ver is unavailable
|
@cptbtptpbcptdtptp @GuoLei1990 关键项处理完毕 |
|
复验结果(基于 488b5b2): ②③④⑤ 验收通过 ✓
但 ①(布局反馈环)还没有动—— 刚在 488b5b2 的新实现上(1:1 含 dpcb observe + fallback)重新实测:真实 DPR=2 屏、默认 CSS 修复方向建议(供参考):pump 应用尺寸前记录 两个小点顺带:
|
… CSS dimensions When a canvas element has no CSS width/height, setting its buffer width/height attributes changes the intrinsic layout size, causing a feedback loop where _resize() inflates the buffer endlessly on each frame. - Guard ResizeObserver fallback against zero client dimensions - Detect layout feedback loop by comparing client size before/after _setSize() - Disable auto-resolution and warn user when loop is detected
@cptbtptpbcptdtptp |
GuoLei1990
left a comment
There was a problem hiding this comment.
复审 @ ecae89589e24(线性追加一个 fix commit:修 no-CSS canvas 的 auto-resize 布局反馈环——① 一次性 fallback 加 clientWidth/Height > 0 守卫防 0×0 buffer;② _pumpPendingResize 在 _setSize 前后快照 clientWidth/Height,检测到布局跟随 buffer 变化即 console.warn + _exitAutoResize() 打破指数发散——闭环 co-maintainer 最后一条真门控 [P1]〔无 CSS 约束反馈环,现 thread RESOLVED〕;--approve 维持 gate 清空)
线性推进检测(审前先校准真 tip)
自我上轮 review(488b5b2827ed)以来 HEAD 线性推进一个 commit(compare 488b5b2827ed...ecae89589e24 = status: ahead / ahead_by: 1 / behind_by: 0,非 force-push;gh api commits/ecae89589e24 --jq .parents = [488b5b2827ed] 父即上轮 tip):
ecae89589e24 fix(rhi-webgl): prevent infinite buffer size growth when canvas lacks CSS dimensions
git diff = 仅 1 文件 packages/rhi-webgl/src/WebCanvas.ts,+23 / -2。因是 fix 前缀,我逐链 trace(非信 commit message)。
逐链核对:布局反馈环检测 —— 闭环 co-maintainer open [P1],修真发散 bug
根因(canvas 是替换元素):无 CSS 宽高时 canvas 的布局尺寸 = width/height 属性。默认 auto 路径成环:pump 读 clientWidth(=当前 buffer)→ 写 canvas.width = clientWidth × dpr × scale(_setSize→_onSizeChanged)→ 改布局 → 下一次 observer 回调拿到更大的 clientWidth → _pendingResize=true → 下帧再放大 → 指数发散。
this._pendingResize = false;
const scale = this._autoResolutionScale;
+ const prevClientWidth = webCanvas.clientWidth;
+ const prevClientHeight = webCanvas.clientHeight;
if (this._pendingDevicePixelWidth > 0 && this._pendingDevicePixelHeight > 0) { ... }
else { ... }
+ if (webCanvas.clientWidth !== prevClientWidth || webCanvas.clientHeight !== prevClientHeight) {
+ console.warn("Canvas layout feedback loop detected: ...");
+ this._exitAutoResize();
+ }逐场景对抗性 trace(检测逻辑,非信描述)——无正确性 bug,无误报,无危险漏报:
- 有 CSS 约束的 canvas(常见路径):
prevClientWidth= CSS 锁定的显示宽(如 800);_setSize写canvas.width = round(800×dpr×scale),但 CSS 约束布局 →clientWidth仍 800;检测clientWidth === prevClientWidth→ 不 warn 不 exit。✓ 无误报——这是关键,正常用户零影响。 - 无 CSS 反馈环:
prevClientWidth= 当前 buffer(如 300)→_setSize写 600(dpr=2)→ 无 CSS 布局跟随属性 →clientWidth变 600 → 检测600 !== 300→ warn +_exitAutoResize()。✓ 第一个发散帧就打破,不等指数放大。 _setSizeno-op(尺寸未变):Canvas._setSize有守卫if (_width !== width),尺寸相同则_onSizeChanged不调 →canvas.width属性不变 →clientWidth不变 → 不误报。✓_exitAutoResize()是否彻底止环:disconnect()observer + 置 undefined(无未来回调)+_pendingResize=false+ 清 pending device px。observer 没了,无未来 pump 会置_pendingResize=true→ 环死。buffer 停在最后一步_setSize的尺寸(一步发散),warn 引导用户加 CSS,可接受。✓- 同步 reflow 可靠性:读
clientWidth强制同步 layout flush(浏览器既有行为),写canvas.width属性后读clientWidth同步返回新布局尺寸 → 检测在真机可靠。✓ - exact 设备像素路径 + 检测交互:检测放在 if/else 之后,同时覆盖 exact 与 fallback 两分支——两条路径都写
canvas.width→ 无 CSS 则clientWidth变 → 检测触发;有 CSS 则 CSS 锁定 → 不误报。✓ - dpr=1 scale=1 边缘(headless e2e):buffer=300 →
_setSize(300)no-op →clientWidth300→300 不变 → 不触发。这不是漏报——此时环处于固定点(300→300),本就无发散;只有buffer≠clientWidth(dpr>1 或 scale≠1)才发散,那些 case 检测都触发。dpr=1 scale=2:300→_setSize(600)→clientWidth变→触发。✓
fallback 守卫(setAutoResolution 无 observer 一次性路径)—— 防 0×0 buffer
- const pixelRatio = window.devicePixelRatio * scale;
- this._setSize(Math.round(webCanvas.clientWidth * pixelRatio), ...);
+ if (webCanvas.clientWidth > 0 && webCanvas.clientHeight > 0) {
+ const pixelRatio = window.devicePixelRatio * scale;
+ this._setSize(Math.round(webCanvas.clientWidth * pixelRatio), ...);
+ }旧:unmounted(clientWidth=0)时 _setSize(0,0) = 0×0 buffer(坏)。新:守卫后跳过。✓ 该路径本就是「无 ResizeObserver = 一次性快照」(小程序语义),守卫只防 0×0,不新增 retry——与既有一次性语义一致,非回归。✓
设计方向(第一性原理复核)—— 检测→warn→exit 是此模型下的正解
对比替代方案:getComputedStyle 前置查 CSS(更重的 layout-forcing 调用 + auto/"" 跨浏览器语义模糊,更脆);observer-fire 前 baseline 快照(更多状态,当前 post-_setSize 比较更简且等价正确)。Three.js/Babylon setSize 同时写 canvas.width + canvas.style.width(强制 CSS),构造上永不成环,但它们的模型不分离 buffer/CSS;Galacean 本 PR 刻意分离 buffer resolution 与 CSS(setResolution ≠ setScale),无法强制 CSS——检测是此分离模型下的务实正解,比竞品更防御(主动检测误配置而非静默假设有 CSS)。非 band-aid:它精准处理真实失败模式(误配置 canvas)且用最佳可得信号。
注释合规 + console.warn 选型
- 两处新
//多句块(:117-119记录快照 why、:135-137检测 why)逐条打开代码验证属实、非 aspirational,解释 why(反馈环机制)非复述代码。末尾句号非 finding::70-71同款多句//块(含句号)在我上轮已 approve 的488b5b2827ed即存在,本 commit 新块跟随同一既有文件惯例(项目惯例 > 教条,且我历史已放行该风格)。 console.warn落在真能力降级路径(canvas 误配置 → auto-resize 无法工作 → 已禁用,用户应知情 + 给出可操作指引「设 CSS 宽高后调 setResolution/setAutoResolution」),选型合规(cr 前置检查 #6)。
核心机制未回退(独立复核 @ tip)
Canvas.ts@tip:read-only width/height getter、setResolutionthrow +Math.round(:41)、_pumpPendingResize/_destroy/** @internal */(:63/65)、_pumpPendingResize基类 no-op、_setSize尺寸守卫 + 单次 dispatch 全在。WebCanvas.ts@tip:read-only scale getter、setAutoResolutionscale throw + OffscreenCanvas 早返回、observerdevice-pixel-content-box+ try/catch +typeof ResizeObserver守卫 + 一次性 fallback(现加 0×0 守卫)、_pumpPendingResize0×0 保留 pending + exact 路径 + Safari fallback + 新增反馈环检测、_exitAutoResizedisconnect + 清 flag、_isOffscreenCanvasinternal 全在。
CI(e2e 3/4 in_progress 非失败,codecov/patch 是比值 artifact)
tip ecae89589e24:build×3〔mac/ubuntu/win〕/ codecov / codecov/project / lint / labeler / e2e 1,2,4/4 SUCCESS;e2e 3/4 in_progress(非失败)。codecov/patch fail = 新增反馈环分支(无 CSS canvas 路径)在真机 headless Chromium e2e(恒有 CSS-sized canvas,不触发反馈环)下不覆盖,是环境特定分支的覆盖率比值 artifact,非测试失败(codecov job 本身 SUCCESS),同历轮判定,不作为 finding。e2e 走真机 resize 路径全绿即实证检测逻辑在有-CSS 常见路径零误报、像素零漂移。
已闭环清单(逐条对 tip 核对,未回退)
- [P1 by cptbtptpbcptdtptp] 无 CSS 约束 auto-resize 布局反馈环指数发散 → 本 commit
ecae89589e24加快照检测 +_exitAutoResize,threadRESOLVED。闭环——co-maintainer 最后一条真门控现已解除。 - [P1 by cptbtptpbcptdtptp] 小程序
new ResizeObserverReferenceError →typeof ResizeObserver守卫,RESOLVED。闭环。 - [P1 by cptbtptpbcptdtptp] content-box 接不住 DPR-only →
device-pixel-content-box,RESOLVED。闭环。 - [P2 by cptbtptpbcptdtptp]
setResolution不整数化 /@internald.ts 泄漏 →Math.round/ 补齐,均RESOLVED。闭环。 - [P2 我] OffscreenCanvas warn 过度触发 → 早前 force-push 撤除。闭环。
- [P0] e2e
resizeByClientSize迁移 → 源码 @tip = 0。[P1] this-loss / lint → SUCCESS。[P2] observe 注释/白屏、isOffscreenCanvas internal、DPR 固化、scale throw、devicePixelContentBoxSize精确设尺、deprecated forwarder 删除、autoResizecreate 选项删除、docs/README 迁移;[P3] pending 标志/字段位置/注释句号/悬挂引用。均关闭、未回退〔本轮仅动 25 行〕。
仍 open(非我 finding,非阻塞,仅记录不重复展开)
cptbtptpbcptdtptp 的 [P3]〔OffscreenCanvas 上显式调用被静默丢弃〕 仍 resolved: false(outdated: true)——该 reviewer 的独立非阻塞 finding,正常展开中,不由我代述或重复。
结论
approve:本轮线性追加一个 fix commit,修 no-CSS canvas 的 auto-resize 布局反馈环——① 一次性 fallback 加 clientWidth/Height > 0 守卫防 0×0 buffer;② _pumpPendingResize 在 _setSize 前后快照 clientWidth/Height,检测到布局跟随 buffer 变化即 console.warn + _exitAutoResize(),在第一个发散帧就打破指数发散——闭环 co-maintainer 最后一条真门控 [P1]〔无 CSS 约束反馈环,现 thread RESOLVED〕。逐 7 场景对抗性 trace 无正确性 bug:有 CSS canvas 检测零误报(关键,正常用户零影响)、无 CSS 首帧即触发、_setSize no-op 不误报(Canvas._setSize 尺寸守卫)、_exitAutoResize 彻底止环、clientWidth 读同步 reflow 真机可靠、检测置于 if/else 后覆盖 exact+fallback 两路、dpr=1 唯一「漏报」是固定点本就无发散的良性 case。设计方向经第一性原理复核是 buffer/CSS 分离模型下的务实正解(对比 getComputedStyle/baseline-snapshot 更简且等价,比 Three.js/Babylon 强制 CSS 更防御地检测误配置)。两处新 // 注释属实合规、末尾句号跟随我上轮已 approve 的既有文件惯例(非 finding)、console.warn 落真降级路径选型合规。核心机制未回退,历史全部闭环项未回退,CI 无失败(e2e 3/4 in_progress 非失败,codecov/patch 是环境特定分支比值 artifact)。我无 P0/P1/P2/新 finding。co-maintainer 全部 P1/P2 现均 RESOLVED,仅剩一条他人 [P3]〔OffscreenCanvas 静默丢弃,非阻塞 + outdated〕不由我重复。因 HEAD 已推过我上轮 approve 的 commit(reviewDecision = REVIEW_REQUIRED),在新 tip ecae89589e24 提交 APPROVE 维持 gate 清空。




概述
一次 canvas 分辨率 API 的易用性增强:把 auto-resize 能力归位到
WebCanvas,让渲染分辨率默认自动跟随显示尺寸——大多数应用create({ canvas })之后不用写任何 resize 代码。主要改动
1. 归属:auto-resize 全部归
WebCanvas,pump 下沉到基类observer 观察 canvas、算 canvas 尺寸、改 canvas 分辨率——概念上 100% 属于 canvas。原本放 engine 是因为白屏修复需要帧时序(实现依赖绑架了归属)。现在:
WebCanvasEngine.update()(this._canvas._pumpPendingResize()),_pumpPendingResize是基类Canvas的默认 no-op、WebCanvasoverride——WebGLEngine不再需要 overrideupdate()2. 默认自动跟随显示尺寸(零配置)
ResizeObserver监听 canvas 元素本身 → 接住窗口、CSS、flex/容器、侧边栏/面板等所有来源的尺寸变化(window.resize只能接住窗口变化)3. 两个分辨率入口
scale的 base 是物理分辨率:1= 满物理分辨率(原生清晰),0.7= 降 30% 提性能,2= 超采样。device pixel ratio 自动吸收,用户无需理解 DPRcreate({ canvas })后调setResolution(w, h)(退出自动,无闪烁)4.
width/height改只读分辨率是原子的整体:单独设
width不动height会产生畸变中间态 + 两次 buffer 重建,且裸写canvas.width会让引擎缓存尺寸与真实 buffer 分叉。改只读后,所有分辨率变更走setResolution一个原子入口。width/height是"画布分辨率"的分量。5. 分数 DPR 精度:
devicePixelContentBoxSizeclientWidth * dpr在分数 DPR(Windows 1.25/1.5)下有 ≤1px 舍入误差。改用ResizeObserverentry 的devicePixelContentBoxSize(精确物理像素)消除它,Safari 等不支持的浏览器自动降级回clientWidth * dpr(特性检测,无人退化)。four 大 web3D 引擎(three.js/Babylon/Pixi/PlayCanvas)均未采用此特性。6. 删
resizeByClientSize被默认自动 +
setAutoResolution覆盖。Breaking Changes
major 版本级:
canvas.width/canvas.height改为只读(用setResolution设分辨率)resizeByClientSizecreate后调setResolution)设计参照
create({...})配置模式对齐 three.js / Babylon(web 引擎标准)scale(物理分辨率之上的性能倍数)对齐 UE ScreenPercentagesetResolution命名对齐 Unity / UE(SetResolution/SetScreenResolution)验证
devicePixelContentBoxSize精确路径 + 首帧时序 jsdom 不忠实复现,靠规范 + 代码审查(建议真机验一次)供讨论。 @luo2430 有不同意见或更好想法请直接回复。