feat(crane_web_debugger): Crane Viewer フルリデザイン(ES module 分割・ドックレイアウト・HUD・リプレイ)#1344
Merged
feat(crane_web_debugger): Crane Viewer フルリデザイン(ES module 分割・ドックレイアウト・HUD・リプレイ)#1344
Conversation
Phase 1+2 の実装。 ## ES module 分割 (Phase 1) viewer.js (1234行のモノリシックファイル) を viewer/ 配下の ES module に分割: - renderer/constants.js: 定数群 - renderer/SvgPathUtils.js: parseSvgPath / svgArcToCanvas - renderer/SvgPrimitiveParser.js: SVGプリミティブパーサー (LRU 40000 に拡張) - renderer/CanvasRenderer.js: Canvas2D レンダラー - renderer/ThemeTokens.js: M3 CSS custom property 読み取り - renderer/FieldLayer.js: viewBox 管理 + turf/grid 描画 - ws/GameControlClient.js: ssl-game-controller WebSocket クライアント - main.js: CraneViewer エントリポイント viewer.html の <script src="viewer.js"> を <script type="module" src="viewer/main.js"> に変更。 window.craneViewer エクスポートを維持し、既存インライン onclick との後方互換性を確保。 ## M3 デザイントークン徹底適用 (Phase 2) - m3e-theme.css に --md-sys-color-field-turf / field-grid トークンを追加 - Canvas 描画の turf (#1a5c1a) / grid (#2d8a2d) / オーバーレイ色をすべて ThemeTokens 経由の M3 トークンに置き換え - prefers-color-scheme 変化・html[class] 変化で自動再取得 ## field_info 動的 viewBox (Phase 2) - world_model.field_info (length/width) を受信して FieldLayer.viewBox を動的更新 - div-A (12×9m) / div-B (9×6m) 等のフィールドサイズに自動対応 - フィールドサイズ変化時のみ pan/zoom リセット - viewBox 変化時に SvgPrimitiveParser のキャッシュを無効化(% テキスト正確変換) ## その他改善 - zoom-to-cursor 対応 (ホイールズームがカーソル位置中心) - ロボットカードのプランナー名を6文字で切り詰めていたバグを修正 (full 表示) - Escape → HALT を確認ダイアログ付きに変更 (2秒以内に再押下で確定)
## レイアウト刷新 - viewer.html を CSS Grid ドックレイアウトに全面書き換え - 左ドック: Game Info / Robots / Game Control / Sim Control - 右ドック: Layer Control / Log Panel - 下ドック: Phase 6 (TimeScrubber) 用プレースホルダー - DockLayout.js: スプリッタドラッグリサイズ + localStorage (cv.dockLayout.v1) 永続化 - CSS var --dock-left-w / --dock-right-w / --dock-bottom-h で制御 - 折り畳みボタン (data-dock-toggle) でアイコンストライプに収納 ## インライン onclick → delegated listener 移行 - GC ボタン全ての onclick 属性を data-action 属性に統一 (gc-command / gc-goals / gc-card-yellow / gc-card-red / gc-next-stage / ball-place / sim-edit / sim-reset-ball / sim-set-endpoint) - main.js に setupDelegatedListeners() を追加 - 生 hex 色を --md-sys-color-team-yellow / team-blue トークンに置き換え ## 生きたログパネル (LogPanel.js) - 差分 append DOM (上限1000件) - level チェックボックス5段 (info/warn/error/action/metric) + テキスト検索 - data-level + CSS セレクタ display:none でフィルタ (DOM 再描画ゼロ) - 自動スクロール (手動スクロールで自動無効化) - WebSocket 接続/切断/エラー/コマンド発行をリアルタイム表示 ## m3e-theme.css - --md-sys-color-team-yellow / on-team-yellow / team-blue / on-team-blue を追加
## RobotHud.js (新規) - 方向矢印: SVG座標系でθに追従、先端V字矢頭、dribble_power > 0 時に色変更 - 選択ハロー: primary=24mm実線 alpha0.8 / secondary(Ctrl+Click)=8mm破線 / hover=6mm破線 - ドリブラーLED: ball_sensor 真→accent / 偽→muted の15mm円 - FSM/Planner ラベル: planning_factors[0].name + planner_name をロボット下方に表示 ## インタラクション強化 (main.js) - Ctrl+Click: _multiSelect Set でセカンダリ選択切り替え - Escape: マルチセレクトがある場合はまず解除 (既存モード解除より後方) - WASD / 矢印キー パン: rAF ループで滑らか、Shift 3倍速 (テキスト入力中は無効化) - robot_feedback ハンドラ追加 (ball_sensor 等) ## ホバーツールチップ (main.js) - mousemove で ROBOT_HIT_RADIUS_M*2 以内の最寄りロボットを検出 - HTML overlay div (#robot-hover-tooltip) をカーソル位置に追従 内容: ID / Pos(x,y,θ) / FSM / Planner - mouseleave でツールチップを非表示 + hover ハロー消去 - fieldToClientCoords() ヘルパーを追加
## Sparkline.js (新規)
- 純 Canvas2D、最大 5 系列、DPR 対応 (width/height オプション)
- setSeries([{ color, data: Float32Array }]) + render(tokens) API
- ゼロ軸 (正負跨ぎ時のみ表示)、末端マーカ円
- MetricRing クラス: 10Hz × 60s = 600 サンプルのリングバッファ
## RobotDetail をドックパネル化 (viewer.html + main.js)
- モーダルダイアログ → 右ドック内インラインパネル (#robot-detail-inline) に変更
- ロボットカードクリックで右ドック RobotDetail セクションに表示
- 表示内容: Mode / Planner / FSM / Pos / θ / Vel / ω / Target / Telemetry リンク
- rAF ループで Pos X / Pos Y / |Vel| の sparkline をリアルタイム更新
- 閉じるボタン (#btn-robot-detail-close) で非表示 + sparkline ループ停止
## MetricRing 更新
- handleWorldModel で robots_ours の x/y/vx/vy から MetricRing に push
- 各ロボット独立に 180 サンプル (10Hz × 18s) を保持
…ase 6) ## RingBuffer.js (新規: replay/) - Two-tier: keyframe 1Hz (svg_data 受信時) + delta (svg_update/world_model/control_targets) - 60 秒ウィンドウ (設定可能)、古いエントリを自動 prune - seek(tsMs): 直前キーフレーム復元 + デルタ適用で任意フレームを再現 - layerStore は Map 深コピーで独立保持 ## TimeScrubber.js (新規: ui/) - 下ドック 44px。レイアウト: [⏮][⏯][⏭] [速度選択] [====●====] [-2.4s] [LIVE] - `<input type="range">` スライダー + ドラッグで seek - キー: [ / ] = ±500ms、Space = 再生/停止、End = LIVE 復帰 - 再生エンジン: rAF で indexMs += dt*speed、最新フレームに到達で LIVE 自動復帰 - LIVE モードでは viewer._replayMode=false でリアルタイム表示を維持 ## main.js / viewer.html - handleSvgData: RingBuffer.addKeyframe で定期スナップショット - handleSvgUpdate / handleWorldModel / handleControlTargets: RingBuffer.addDelta で tee - _replayMode=true の間は Store 更新をスキップ (RingBuffer にのみ書き込む) - DockLayout のデフォルト bottom を 44px に変更 (TimeScrubber 表示) - viewer.html に #time-scrubber-container を配置
RingBuffer.js に indexBy・applyLayerUpdate を共通ヘルパとして追加し、 main.js・RingBuffer の両所で重複していた実装を統一した。 変更内容: - indexBy(arr, keyName): 配列→キー付きオブジェクトの変換ヘルパを追加 robots_ours/theirs・control_targets の変換箇所で利用(5 箇所) - applyLayerUpdate(layerStore, upd): レイヤー状態変更ロジックを抽出 replace/append/clear の分岐が main.js と RingBuffer で乖離するリスクを解消 - findRobotAtPosition: _nearestRobot の薄いラッパーに簡略化(重複実装を削除) - _updateTooltip: _hoveredTooltipId で変化検出し、同一ロボット上での mousemove による innerHTML 再パースを回避 - coalesceLayerUpdates: replace/append-after-clear の [...]clone を除去し downstream の applyLayerUpdate に一本化(ダブルクローン解消) - updateGcPanel: ts['YELLOW'] → ts.YELLOW、プレースホルダを '--' に統一 - WHAT コメント 5 箇所削除
ホストの web/ ディレクトリを volume mount すると Docker ビルド時に ダウンロードしたフォントが上書きされ 404 になる問題を修正した。 変更内容: - Dockerfile: --output-dir /app/fonts を追加し、フォントを volume mount 対象外の /app/fonts/ に配置するよう変更 - app.py: FONTS_DIR 環境変数(デフォルト /app/fonts)の ディレクトリを /fonts URL として StaticFiles で配信 - *.html (4 ファイル): フォント参照パスを相対 assets/fonts/ から 絶対パス /fonts/ に変更 - download_fonts.py: キー名 "material-symbols" を "material-symbols-outlined" に修正(生成 CSS 名が HTML 参照名と 一致しておらず常に 404 になっていたバグを同時修正)
c9a7ff2 to
113fb57
Compare
| const newZoom = Math.min(Math.max(this.zoomLevel * factor, 0.1), 5.0); | ||
| const zoomRatio = newZoom / this.zoomLevel; | ||
| // パンオフセットを調整してカーソル下のフィールド座標を固定 | ||
| const fl = this.fieldLayer; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
概要
crane_web_debuggerの viewer を全面リデザイン。モノリシックな viewer.js を ES module に分割し、ドックレイアウト・ロボット HUD・Sparkline・RingBuffer リプレイ・フォント配信修正まで一括実装。背景・根本原因
旧 viewer.js は単一ファイルに全機能が詰まっており保守性が低かった。また UI がフラットで情報密度が低く、試合中の状況把握に不要な操作が多かった。
変更内容
Phase 1-2: ES module 分割・M3 トークン・動的 viewBox
viewer/renderer/に CanvasRenderer・FieldLayer・RobotHud・SvgPrimitiveParser・SvgPathUtils・ThemeTokens・constants を分離Phase 3: ドックレイアウト・パネル分割・ライブログ
viewer/ui/DockLayout.js: 左・右・下ドックをスプリッターで可変リサイズ、localStorage 永続化viewer/ui/LogPanel.js: level フィルタ・テキスト検索付きライブログパネルPhase 4: ロボット HUD・インタラクション強化
viewer/renderer/RobotHud.js: 方向矢印・FSM/planner ラベル・ドリブラー LED・ホバーハロー・マルチセレクトPhase 5: Sparkline・RobotDetail ドックパネル化
viewer/ui/Sparkline.js+MetricRing: 位置 X/Y・速度の 60fps リアルタイム SparklinePhase 6: RingBuffer・TimeScrubber による 60s リプレイ
viewer/replay/RingBuffer.js: キーフレーム(1Hz)+ デルタ(60fps)の 2 層バッファで 60 秒巻き戻しviewer/ui/TimeScrubber.js: 下ドックに再生・一時停止・速度変更・スクラブ・LIVE 復帰 UIrefactor: JS 共通化・簡潔化
indexBy/applyLayerUpdateを RingBuffer.js から export し、main.js と RingBuffer の重複実装を統一findRobotAtPositionを_nearestRobotのラッパーに簡略化fix: フォント 404 解消
web/assets/fonts/を上書きする問題を修正/app/fonts/(mount 外)にダウンロード/fonts静的配信ルートを追加(FONTS_DIR環境変数対応)material-symbols-outlined.cssのファイル名不一致バグを修正