zudo-panel-designer docs
GitHub リポジトリ

検索したい単語を入力

いつでも検索バーを開ける

インターフェース

エディタ(Editor.tsx)は、4 つの領域を持つ 1 枚のフルスクリーンシェルです。ヘッダー、左ツールバー、中央のキャンバスビューポート、右サイドバーで構成されます。シェルが保持するのは汎用的な状態だけです。ドキュメント(undo/redo 履歴を含む)、カメラ、現在の選択、そしてどのツールがアクティブか、という状態です。ドメイン固有の要素はすべて、拡張レジストリが公開するデータからレンダリングされます。そのためこのページでは、レジストリが登録済みになった状態での UI の挙動を説明します。

ヘッダー

components/header.tsx は最上部のバーです。左から右へ、次の要素が並びます。

  • アプリ名。

  • ズーム操作のまとまり。ズームアウト / ズームインボタン(25% 刻み)、現在のズーム率(物理的な mm ではなく「フィット」スケールに対する相対値)、そしてパネル全体が収まるようにカメラを再センタリング・再スケールする Fit ボタン。

  • undo / redo ボタン。undo/redo できる対象がないときは無効化されます。

  • キーボードショートカットのダイアログを開く ? ボタン。

  • 現在のドキュメントを発注可能なパネル設定 JSON としてダウンロードする ⬇ JSON ボタン(後述の ダウンロードトリガー を参照)。

左ツールバー

components/toolbar.tsx は完全にデータ駆動です。ツールレジストリの各エントリを登録順に 1 つずつボタンとしてレンダリングし、続いて区切り線を挟んで 追加アクションレジストリの各エントリを 1 つずつボタンにします。ツールボタンをクリックすると ctx.setActiveTool(tool.id) が、追加アクションのボタンをクリックすると action.run(ctx) が呼ばれます。どちらのリストも手作業で管理するものではありません。tools/add-actions/ に新しいファイルを置くだけで、自動的にここへ現れます。組み込みのツール一式については ツール を参照してください。

キャンバスビューポートとルーラー

components/canvas-viewport.tsx は、単一の <canvas> を包む、純粋に表示だけを担うラッパーです。containerRefResizeObserver で計測し、リサイズ時にカメラが再フィットできるようにする)を公開し、ポインタイベントを Editor シェルへ転送します。<canvas> 自体には touch-action: none が指定されており、タッチデバイスでドラッグがスクロールやピンチのジェスチャーとして横取りされないようにしています。実際の描画はすべて Editor の再描画エフェクトで行われます。レンダリングとカメラ を参照してください。

ビューポートは、固定された ルーラーフレームcomponents/ruler.tsx)の内側に収まります。上辺には 20px のミリメートルルーラーの帯、左辺にはそれと対になる帯、そして両者が交わる左上には小さな mm のコーナーボックスが置かれます。これらの帯は、カメラがパンやズームをするたびに目盛りとラベルを描き直しますが、レイアウト上は決して動きません。動くのはキャンバスの内容だけで、帯自体はその下で静止しています。目盛りの計算については レンダリングとカメラ → mm ルーラー を参照してください。

右サイドバー

components/sidebar.tsx は、折りたたみ可能なカードパネル を縦に積み重ねたものです。上の 4 つはスクロールする内側の列を共有し(overflow-y-auto overscroll-contain なので、リストが下端まで来ても背後のキャンバスがスクロールすることはありません)、Help パネルはその下に、スクロールしないフッターとして固定されます。上のスタックがあふれても常に見えたままです。

各パネルは CollapsibleSectioncomponents/collapsible-section.tsx)です。枠線付きのカードで、そのヘッダーがボタンになっており、本体の開閉を切り替えます(ボタンに aria-expanded/ のインジケーター付き)。開閉の状態はセッション単位で、意図的に永続化されません。並べ替えやアニメーションもありません。

  • Panel — 実在する Eurorack の HP サイズ(@zpd/corePANEL_SIZES)を並べた <select>。各項目は {hp}HP — {widthMm}×{heightMm}mm とラベル付けされます。変更するとドキュメントに新しい panelHp がコミットされ、カメラが再フィットされます。

  • Palette (fixed) — パネルの 3 色(黒/ソルダーマスク、金/露出した銅、白/シルクスクリーン)を示す読み取り専用の凡例。このリストはユーザーの好みではなく物理的な PCB の仕上げを反映しているため、固定されています。

  • Layerscomponents/layer-list.tsx。レイヤースタックを視覚的に表示します(リストの一番上 = スタックの最上位 = 配列の最後のインデックス)。各行では、選択(クリック)、名前変更(名前をダブルクリック)、並べ替え(▲/▼)、表示/非表示(👁)、削除(✕)ができます。これらはすべて @zpd/core の layer-ops を経由するため、順序や不変性のルールが 1 か所にまとまっています。

  • Propertiescomponents/inspector-host.tsx。選択中のレイヤーの型に登録された インスペクタ をレンダリングします。何も選択されていないときはプレースホルダーを表示します。カードのタイトルには、選択中のレイヤーの型も表示されます(例: Properties — shape)。

  • Help(フッター) — components/help-panel.tsx。サイドバーの一番下に固定され、初期状態では折りたたまれています。現在 アクティブな ツールを説明します。ツール名、キーボードショートカットのバッジ、そしてツールの description テキストです(ツール拡張アーキテクチャ を参照)。表示は activeToolId に追従するため、Space を押している間の一時的なパンのオーバーライドで内容が変わることはありません。

アプリ全体でのテキスト選択

エディタシェルのルート要素には select-none が指定されているため、クロムやキャンバスのどこをクリック&ドラッグしても、ネイティブのテキスト選択が始まることはありません。これにより、レイヤーの移動・パン・ペンパスの描画といったドラッグのジェスチャーが、操作の途中で UI のラベルを誤ってハイライトしてしまうのを防ぎます。編集用のフィールドは select-text で明示的に選択を有効化しているため(レイヤー名の変更用入力、インスペクタの数値/テキストフィールド、テキストインスペクタの <textarea>)、その中身は通常どおり選択・編集できます。

ダウンロードトリガー

ヘッダーの ⬇ JSON ボタンは download.tsdownloadPanelConfig(ctx.doc) を呼び出します。この関数は次の処理を行います。

  1. @zpd/coreserializePanelConfig(製造側のリーダーが期待する正規の形)でドキュメントをシリアライズし、JSON.stringify します。この処理は DOM に依存しない純粋な panelConfigJson() ヘルパーとして切り出されており、実際の Blob やアンカーなしで出力文字列そのものをユニットテストできます。

  2. 文字列を Blob に包んでオブジェクト URL を作成し、一時的な <a download> のクリックによって zpd-panel-{panelHp}hp.json という名前でブラウザのダウンロードを発火させます。

  3. オブジェクト URL の破棄は即座にではなく、遅延した tick(setTimeout(..., 0))で行います。クリックと同じ tick で破棄すると、ブラウザによっては blob を読み終える前にダウンロードが中断されることがあるためです。

これはあくまでエディタ側のトリガーです。エクスポートされる JSON の形と、それが下流でどう利用されるかについては、エクスポートのセクションで解説します。

Note

このセクション全体で参照しているドキュメントモデル、undo/redo 履歴、レイヤーの型(DocStateLayerPATTERN_GENERATORSserializePanelConfig など)は @zpd/core@zpd/patterns にあり、ドキュメントモデルのセクションで解説します。