# PHYレイヤー ## 概要 PHYレイヤーは、キースイッチやキーキャップ、その他周辺部品の物理的な配置に関する情報を提供する。 付加的な情報として、matrix情報(ELCレイヤー)や入力キー情報(MAP/IMEレイヤー)を含ませることができるが、必須ではない。 ## 構造 ### キースイッチ/キーキャップの配置 各キーはスイッチ・キャップの情報を統合された状態で持ち、キャップの位置・サイズからスイッチ座標を特定する。 以下、単に「キー」と呼ぶ場合、キーキャップの位置・サイズを表すオブジェクトをさすこととする。 ### プロファイル設定 1ファイル内に複数のプロファイルを持たせることができる。 ユニットサイズ(1Uが何mmか、x軸・y軸それぞれ)を規定。 ビジュアル表現として、内側へのオフセット位置及びオフセット距離(mm or U単位)・R(U単位)を規定。 ### 座標と回転 各ノードは、親ノードから見た相対的な配置を持つ。絶対座標は保持しない。 クラスター単位の移動・回転を親ノード1つの書き換えで済ませるため、相対座標を正本とする。 配置は「親の座標系で θ 回転してから (x, y) 平行移動」と定義する。 ```txt p_parent = Translate(x, y) · Rotate(θ) · p_child ``` この定義により、(x, y) は自分のローカル原点が親座標系のどこに来るかを表し、θ は自分の向きを表す。 回転軸は常に自分自身のローカル原点であり、パラメータとしては持たない。 キーもクラスターも同じ変換を持つため、キーごとに向きが異なる配置のためにクラスターを作る必要はない。 ローカル原点はキーキャップの左上角とする。座標単位はU。1Uのサイズはプロファイルで指定する。 座標・回転角度は、ローカル座標系で0.25U単位・15度単位でスナップするが正規化しない。 KLE JSONやPCB向けの出力は、階層を畳んで絶対座標に変換した導出物として生成する。 ### キーのサイズ 0.25U単位でスナップするが正規化しない。 サイズはローカルの値であり、親の変換を受けない。 ### グルーピング 複数のキーを「クラスター」としてまとめて運用することができる。 クラスターのみにフォーカスして編集が可能。 クラスターの原点が、配下のノードの回転中心になる。 **内部処理での利用**: - クラスターごとの一括編集・移動・回転 - 階層構造による管理(クラスターの入れ子構造) - 編集時のフォーカス制御 - 回転中心を保存したい場合はクラスターにする(ノード自身は回転中心を持たないため) **外部連携での扱い**: - KLE JSON出力時は、個別のキー配置のみを出力(クラスター情報は含めない) - 別途クラスター情報JSONとして構造を保存 - キーIDによる紐づけで関連性を管理 ### 何かある? ## 保存形式 各ノードは親から見た変換を持つ。キーとクラスターを混在させた木構造として保持する。 ```ts type Transform = { x: number, // 親座標系での位置 y: number, rotation: number // 親座標系での回転角度(度) } type Size = { w: number, // ローカル値。親の変換を受けない h: number } type Key = { transform: Transform, size: Size, profile: Profile } type Cluster = { transform: Transform, children: (Key | Cluster)[] } const root: (Key | Cluster)[] = [] ``` ## 連携用出力形式 ### 設計方針 KLE向けの出力は既存のKLE JSON形式を維持し、クラスター情報は別のJSONファイルとして出力する。 両者の紐づけは、KLEのlabel部分に埋め込むユニークIDを使用する。 ### KLE JSON出力 標準的なKLE JSON形式で出力。各キーのlabelにはユニークIDを含める。 ```ts type ConfigObject = { x?: number, y?: number, w?: number, h?: number, x2?: number, y2?: number, w2?: number, h2?: number, rx?: number, ry?: number, ra?: number, l?: boolean, n?: boolean, d?: boolean, c?: string, t?: string, g?: boolean, a?: number, f?: number, f2?: number, p?: string, s?: string } type KeyLabel = string // ユニークID + 表示用ラベルを含む const kleData = (ConfigObject | KeyLabel)[][] ``` ### クラスター情報JSON キーのクラスター構造を管理する別ファイル。 ```ts interface ClusterInfo { id: string, // クラスターのユニークID name?: string, // 表示用クラスター名 position?: Position, // クラスター自体の位置・回転情報 keyIds: string[], // 所属するキーのIDリスト subClusters?: string[] // 子クラスターのIDリスト(ネスト構造用) } interface ClusterData { version: string, profiles: Profile[], // プロファイル定義 keys: { // キーID -> 追加情報のマップ [keyId: string]: { originalLabel?: string, // KLEのlabelから抽出した表示用文字列 matrix?: MatrixPosition, // matrix情報(オプション) mapping?: KeyMapping // キーマッピング情報(オプション) } }, clusters: ClusterInfo[] // クラスター構造定義 } ``` ### 出力例 #### keyboard.json (KLE形式) ```json [ ["key-001\nQ", "key-002\nW", "key-003\nE"], ["key-004\nA", "key-005\nS", "key-006\nD"] ] ``` #### keyboard-clusters.json ```json { "version": "1.0.0", "keys": { "key-001": { "originalLabel": "Q", "matrix": [0, 0] }, "key-002": { "originalLabel": "W", "matrix": [0, 1] }, "key-003": { "originalLabel": "E", "matrix": [0, 2] }, "key-004": { "originalLabel": "A", "matrix": [1, 0] }, "key-005": { "originalLabel": "S", "matrix": [1, 1] }, "key-006": { "originalLabel": "D", "matrix": [1, 2] } }, "clusters": [ { "id": "cluster-alpha", "name": "英字キー", "keyIds": ["key-001", "key-002", "key-003", "key-004", "key-005", "key-006"] } ] } ``` ### 分離設計のメリット この設計により以下の利点が得られる: 1. **KLE互換性の維持**:既存のKLE関連ツールとの完全な互換性を保持 2. **柔軟な拡張性**:クラスター情報を独立して管理・拡張可能 3. **段階的移行**:既存のKLEユーザーが段階的に拡張機能を利用可能 4. **ツール間連携**:KLE標準形式での出力により、他のキーボード設計ツールとの相互運用性を確保 5. **データの軽量化**:KLE出力時に不要な情報を含めず、ファイルサイズを最小化 ## 検討済み・非採用 - キーごとの絶対座標保持 (journal/2026-09-18-phy-coordinate-model.md) - 相対座標と絶対座標の併記 (journal/2026-09-18-phy-coordinate-model.md) - ノードごとの回転中心パラメータ (journal/2026-09-18-phy-coordinate-model.md) ## 未確認事項 ### P-1 KLE JSONへ書き出した配置が行のまとまりを保てるか - 位置づけ: 本文が前提にしているものではない。連携用出力形式の設計に関わる未解決の問い - 現状の認識: 階層を畳んでKLEに読み込ませると行のまとまりが崩れる。他レイヤーの情報を使ってでも行ごとにまとめたいが、方法は未検討 - 格上げ条件: 回転を含むPHYデータをKLE JSONに変換してKLE本家に読み込ませ、rotation groupと行配列がどう再構成されるかを確認する