D-20260811-08|玩家動態偏好與單一有效狀態¶
背景與驅動力¶
設定 canon 原先宣告 reducedMotion: boolean,實作卻只有 CSS 的作業系統
prefers-reduced-motion media query。玩家不能在遊戲內主動要求減少動態效果,CSS 特例、
3D 展示自轉與未來裝飾性動態也沒有共用的有效狀態。專案仍在開發期,因此直接修訂未發布
資料模型,不保留舊欄位或遷移相容層。
考慮過的選項¶
- 各頁自行合併玩家設定與 media query:會重複 listener 與語意,未來 consumer 容易分歧,棄。
- 只把結果投影到 DOM,非 CSS consumer 每幀讀 attribute:改動較小,但把執行期邏輯耦合到 presentation DOM,棄。
- 建立集中式 motion preference service,讓 DOM、CSS 與 3D consumer 共用有效狀態(採納)。
決定¶
DisplaySettings使用motionPreference: 'system' | 'reduce'。default 與 sanitizer fallback 均為system;不接受舊reducedMotion、alias 或 migration。system跟隨 OS,reduce只能 增加保護,不能覆蓋 OS 的 reduce 偏好。- 唯一 effective reduced motion 為「玩家選 reduce,或 OS media query 為 reduce」。runtime
只建立一個
MediaQueryListlistener,OS 偏好變更立即重算,生命週期結束時解除 listener。 - 靜態與 SSG HTML 初始使用
data-motion="pending"。pending 與 reduce 都套用 motion safety; 只有 browser 已載入設定且確認有效狀態為 full 時才改成data-motion="full"。沒有 DOM、沒有matchMedia或 JavaScript 啟動失敗時維持 fail-safe pending。 - CSS safety 同時守住 OS media query 與 root
data-motion。通用動畫/轉場近乎立即、迭代一次、 smooth scroll 關閉;animation: none、transform: none等特例也要有 attribute 等效路徑。 原本只在no-preference啟用的裝飾動畫改由data-motion="full"守門,pending 不得播放。 - Home、Garage 與 Result 的
vehicle-showcasedescriptor 仍只表達「此場景允許自轉」。Viewport render loop 讀共享 effective signal;reduce 時停止增加內容群組角度,full 後從原角度續轉, 不重建 scene、vehicle、camera 或 renderer。 - motion preference 只控制非必要 presentation。不得停止比賽物理、Viewport render loop、
Editor、必要比賽鏡頭追蹤、HUD、gamepad polling、network 或 spectator 更新。
effectsQuality仍是效能/畫質軸,與動態舒適度正交。 - 設定頁提供「跟隨系統/減少動態」兩段選項與說明,未登入可用且立即持久化;display reset、 本機備份 round-trip、四語 i18n、鍵盤與螢幕閱讀器標示使用既有設定契約。
後果與影響¶
所有現有及未來非必要動態有單一可測試的 runtime source,SSR 與 IndexedDB 載入空窗不會先
播放再突然停止。Viewport 仍持續 render,因此控制項、資產載入與場景呈現不中斷;只略過展示
內容群組的角度增量。代價是新增一個 root-scope service,並需逐一把現有 reduced-motion CSS
特例接到 data-motion safety,但不增加網路、共識或 gameplay 狀態。