Skip to content

HUD Shared Core

罐頭 edited this page Sep 3, 2026 · 1 revision

HUD Shared Core

HUD style 是可替換的視覺層;資料接收、單位整理、frame pacing、生命週期和跨 iframe 傳送則由 shared core 統一處理。本頁說明這些共用模組的維護邊界。樣式實作請看 HUD 開發指引,共用卡片請看 HUD Telemetry Cards。

核心組成

模組 主要責任 維護時的重點
shared/ws.js 連接 /ws/telemetry 與 /ws/overlay、重連、轉發事件 不要讓每個 HUD iframe 各自連線
shared/coordinator.js 整理 canonical telemetry、單位、紅線、session maxima、lockup 任何欄位改動都要同步所有 consumer
shared/frame-interpolator.js 以 timestamp 在渲染時間點插值連續/角度/陣列資料 只對適合插值的欄位使用,離散狀態不可誤插值
shared/hud-core.js style registry、config/elements/frame/audio/media dispatch、scale、destroy Core 是 iframe 內唯一的 style lifecycle authority
shared/overlay-forwarding.js 將高頻 audio/media 更新排程後送入 HUD 控制轉送頻率,避免 postMessage 風暴
shared/overlay-dedupe.js 以序號或 media fingerprint 去除重複事件 不可吞掉真正變更的媒體狀態
shared/hud-base.css root wrapper、字型、透明視窗與共用佈局 不要在 style 內破壞外層定位契約
shared/telemetry-cards.js 對外 re-export manager、template、cards、utils 詳細資料契約見獨立卡片頁

事件路徑

sequenceDiagram
    participant B as Backend
    participant W as shared/ws.js
    participant C as coordinator
    participant H as launcher host
    participant I as HUD iframe
    participant K as HUDCore

    B->>W: /ws/telemetry
    W->>C: telemetry event
    C->>H: hud:frame
    H->>I: postMessage(hud:frame)
    I->>K: handleMessage
    K->>I: activeStyle.onFrame(data, payload)
    B->>W: /ws/overlay
    W->>H: hud:config/audio/media/animate
    H->>I: postMessage(event)
    K->>I: dispatch corresponding hook
Loading

hud_overlay/index.html 是 host。它初始化共用卡片、接收 BroadcastChannel horizon_tuner_hud_channel 的控制訊息、依 /api/hud/styles 建立 style URL,然後把事件送到目前的 iframe。一般 style 不應直接改這個 host;需要新增共用協定時才修改,並先確認所有樣式仍可載入。

Canonical telemetry

coordinator 將原始 UDP packet 保留在輸出物件中,同時提供 style 可直接使用的語意欄位:

類別 欄位例子 說明
時間/車輛 timestamp_ms、carOrdinal、isRaceOn frame 時間與車輛切換判斷
引擎/速度 rpm、maxRpm、idleRpm、redlineRpm、speed、speed_kmh、speed_mph、gear 由 raw 欄位整理,紅線基準為 maxRpm - 1000
動力 power、power_hp、power_kw、power_ps、torque、torque_nm、torque_ftlbs 依 displayUnits 提供顯示值與原始換算值
增壓 boost、boost_psi、boost_bar、boost_kpa、boost_unit 非負值並依設定選擇顯示單位
輸入 throttle、brake、clutch、hand_brake、steer 油門/煞車/離合器為 0 到 1,方向盤保留輸入語意
四輪 TireTemp、tire_temp_f、slip_fl 等、slip_angle_fl 等、susp_fl 等 固定 FL/FR/RL/RR 順序
動態 accel_x/y/z、vel_x/y/z、heading_deg、pos_x/y/z G-force、漂移、Live Map 等使用
衍生狀態 sessionMaxima、lockup、lcState coordinator 統一計算,style 不要另做第二版本

單位原則

coordinator 讀取 window._currentHudConfig.effectiveUnits,再依 speed、power、torque、boostPressure 決定顯示值。樣式應使用 data.displayUnits、對應的 *_unit 和已轉換欄位,不要看到 raw PowerWatts 就在每個頁面各自換算。胎溫的共用 raw 顯示基準是華氏;要顯示攝氏時使用共用 helper 或明確的單位轉換。

紅線、session maxima、lockup

  • redlineRpm 由 EngineMaxRpm 減去 1000 得到;視覺上的弧線、分段或 sprite mapping 可以不同,但基準應相同。
  • sessionMaxima 追蹤 power、torque、boost;換車時會重置 baseline,避免新車沿用舊車峰值。
  • lockup 以煞車比例與各輪 slip ratio 判斷,提供 fl、fr、rl、rr boolean;Advanced 等 HUD 可直接使用。

Frame pacing 與 smoothing

coordinator 會把收到的 telemetry sample 推入 FrameInterpolator,再在 render loop 以 performance.now() 取出當下 frame。連續數值可 lerp,角度使用 degree-aware interpolation,陣列依欄位規則處理;檔位、race state 等離散資料不可當作連續數值平滑。

控制面板的 enableSmoothing 會切換 coordinator 的 frame smoothing。style 若要做自己的視覺平滑,應保存小型 state,在 render loop 中 lerp,並於 hud:destroy 清理;不要深拷貝整個 telemetry 或把每個 hook 都變成一個獨立 timer。

HUDCore 生命週期

HUDCore.registerStyle('my_style', {
    containerId: 'myStyleContainer',
    scaleMultiplier: 1.0,
    onInit: function (payload) {},
    onElementsChange: function (elements) {},
    onFrame: function (data, payload) {},
    onAudio: function (data) {},
    onMedia: function (data) {},
    onAnimate: function () {},
    onScale: function (scale) {}
});
HUDCore.init('my_style');

收到訊息後,Core 的責任是:

  1. hud:config 更新 window._currentFullConfig、色彩/glow CSS variables 和 elements;
  2. hud:elements 呼叫 onElementsChange;
  3. hud:frame 將 data 和共用 payload 傳給 onFrame;
  4. hud:audio、hud:media 分別傳給選填 hook;
  5. hud:init 呼叫 onInit,hud:animate 呼叫 onAnimate;
  6. hud:set-scale 計算 scaleBaseline * scaleMultiplier * userScale,一般情況只更新 containerId 的 zoom;
  7. hud:reload/hud:destroy 清理 style 與 TelemetryCardsManager,避免 listener/animation loop 殘留。

style 只有在內部 Canvas、字型或 layout 需要跟著最終 scale 做額外處理時才提供 onScale。外層定位由 .hud-root-wrapper 控制,不要把 scale 和螢幕座標分散在各樣式。

訊息與通道維護

訊息 方向 資料 典型用途
hud:frame coordinator → host → iframe data + redlineRpm、sessionMaxima、lockup 等 60Hz 車況
hud:config control/backend → host → iframe 完整 overlay config style、色彩、單位、卡片設定
hud:elements control → iframe elements map 顯示開關
hud:audio overlay WS → host → iframe 32-band spectrum、VU、success VFD/音訊視覺化
hud:media overlay WS → host → iframe title、artist、status、success 媒體文字/狀態
hud:animate control → host → iframe 無或少量 payload 啟動 sweep
hud:set-scale control → iframe user scale 動態 zoom
hud:reload / hud:destroy host → iframe style lifecycle 切換或關閉

增加訊息時,至少同步更新 sender、host relay、Core handler、型別/測試與本頁。高頻事件應經 overlay-forwarding 排程,能以 sequence/fingerprint 去重時先去重;不可為了方便在每個 style 直接輪詢 API。

維護與除錯

遇到所有 HUD 同時停止,先查 backend WebSocket、ws.js 與 coordinator;只有單一 style 異常才查該 style 的 hook、Canvas、asset 和 DOM。遇到畫面持續累積或 CPU 上升,檢查:

  • style 切換後是否仍有舊的 message listener;
  • requestAnimationFrame 是否重複啟動;
  • audio/media 是否有第二條 WebSocket 或未去重的轉送;
  • card history 是否在 disconnect/paused 後清理;
  • onFrame 是否執行 deep copy、建立 DOM 或呼叫昂貴 API。

修改 shared core 後,至少做 syntax/test、連線中斷重連、切換 style、切換單位、Launch/Reload/Destroy 多次、10 個內建 HUD 的 smoke test。若改動 canonical 欄位,還要更新 HUD Telemetry Cards 與 HUD 樣式參考 的相關欄位說明。

來源檔案

English

Shared Core owns transport, canonical telemetry, interpolation, iframe messaging, style lifecycle, and cleanup. Styles should consume hud:frame and common config rather than opening their own WebSocket or recalculating units, redline, maxima, or lockup. Changes to a shared event or canonical field require checking the host, HUDCore, all built-in styles, tests, and the related Wiki pages.

日本語

Shared Core は通信、canonical telemetry、補間、iframe メッセージ、スタイルのライフサイクル、後片付けを担当します。各スタイルは独自 WebSocket を開いたり、単位・レッドライン・最大値・ロックアップを再計算したりせず、hud:frame と共通設定を使用してください。共通イベントや canonical field を変更した場合は host、HUDCore、全内蔵スタイル、テスト、関連 Wiki を確認します。

Clone this wiki locally