PHY: レイアウトバリアントを木のノードとして導入し、ELC/IDXの扱いを決める

交換可能なキークラスタ(ISO Enter、スペース周りのキー数など)を、
VariantGroup / Variant の2ノードでPHYの木に表す。全バリアントのキーを
同時に持ち、単一の配置を要求する出力のときだけ1つ選んで畳む。

ELCは選択に関係なくsupersetを配線する。排他キー同士は同じ接続先を共有してよい。
IDXはキー番号の空間を1つに保ち、同じ接続先に配線された排他キーは
`order` の配列要素として同じ番号を共有する。

Journal: journal/2026-09-21-multi-layout.md

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JPCpuPv6hDN76RgNe2PsRR
This commit is contained in:
2026-09-21 09:34:51 +09:00
co-authored by Claude Opus 5
parent 2eb2867c13
commit a175ee3c53
6 changed files with 296 additions and 23 deletions
+62 -5
View File
@@ -124,6 +124,41 @@ IDXはLEDの番号を持たない。RGB効果が必要とする位置と区分
- クラスター構造はBeyond KLEのデータにのみ存在する。外部形式へは階層を畳んだキー配置だけを出力する
### レイアウトバリアント
一部のキークラスタを別の構成と交換できるようにした基板がある。
`\ |` と `Enter` を ISO Enter と1Uキーに変える、スペースキー周りのキー数を変える、といったもの。
交換にはスイッチの差し替えが伴い、同時に成立するのは1つだけである。
PHYは全バリアントのキーを同時に持つ。基板上のフットプリントは選ばれなかった側も実在するため、
どれか1つに畳んだ状態を正本にできない。
排他関係は木構造で表す。バリアントグループ(VariantGroup)と、その子であるバリアント(Variant)の
2種類のノードを置く。Variantの配下にあるノードが、そのバリアントを選んだときに実装されるものになる。
- VariantGroupの子はVariantだけ。VariantはVariantGroupの直下にしか現れない
- 選択肢が3つ以上ある場合はVariantを3つ以上置く
- 配下にノードを持たないVariantを置いてよい(「エンコーダーを載せない」など)
- 部品ノードもVariantの配下に置ける。1Uキーとロータリーエンコーダーの選択がこれにあたる
- Variantの中に別のVariantGroupを置ける。あるバリアントを選んだときだけ現れる選択肢を表す
- 選択箇所が複数ある場合はVariantGroupを複数置く。同じ親の下に並べてよい
VariantGroupはクラスターと同じ変換を持つ。Variantは変換を持たない。
バリアントは同じ場所を占める代替物であり、選択によって配下の絶対配置が動く構造を作らないため。
1つのバリアントの中で回転中心が要る場合は、その中にクラスターを置く。
サイズや形が変わるキーは、同じキーを書き換えるのではなく、別のキーノードとして各Variantに置く。
ANSI EnterとISO Enterは別のIDを持つ2つのキーであり、同じ場所に重なる。
VariantGroupは既定のバリアントを1つ持つ。KLE JSONのように単一の配置を要求する出力は、
VariantGroupごとにバリアントを1つ選んでから階層を畳んで生成する。既定値はそのときの初期選択になる。
編集中にどのバリアントを表示しているかはエディタの状態であり、PHYには保存しない。
Variantをまたぐノードの移動は、クラスター間の移動と同じreparentとして扱う。絶対配置は変わらない。
組み替えの対象を同一の親に限る規則がそのまま効くため、複数のVariantにまたがる選択は組み替えできない。
選択はPHYを畳むときにだけ使う。他レイヤーはPHYのノードIDを参照するだけで、選択を見ない。
### クラスターの組み替え
クラスター構造は、配置を作ったあとから組み替える。KLE JSONから取り込んだ平坦なキー配置に
@@ -151,7 +186,7 @@ Transform は回転と平行移動だけを持つ剛体変換であり、合成
## 保存形式
各ノードは親から見た変換を持つ。キー・クラスター・部品ノードを混在させた木構造として保持する。
各ノードは親から見た変換を持つ。キー・クラスター・部品ノード・バリアントノードを混在させた木構造として保持する。
各ノードはIDを持つ。木の中のノードを一意に指すために持ち、キーのIDは他レイヤーからの参照にも使う。
```ts
@@ -186,12 +221,25 @@ type Component = {
transform: Transform,
partGroup?: string // `@` 始まりは描画用の予約名
}
type Node = Key | Cluster | Component | VariantGroup
type Cluster = {
id: string,
transform: Transform,
children: (Key | Cluster | Component)[]
children: Node[]
}
const root: (Key | Cluster | Component)[] = []
type VariantGroup = {
id: string,
name: string, // UI上の選択肢の見出し
transform: Transform,
default: string, // 既定のVariantのid
children: Variant[] // 2つ以上。並びが表示順
}
type Variant = {
id: string,
name: string,
children: Node[] // 空でもよい
}
const root: Node[] = []
```
## 連携用出力形式
@@ -245,6 +293,7 @@ const kleData = (ConfigObject | KeyLabel)[][]
- 回転角度は正規化せずそのまま出力する。KLEのデータは任意の角度を受け付け、15度刻みはKLEのUI上の操作単位にすぎない
- rx, ry はPHYに持たないので、出力時に選ぶ
- ユニットサイズ(mm)、ビジュアルオフセット、クラスター構造、部品ノード、per-key LEDはKLE JSONに出力されない
- バリアント構造はKLE JSONに出力しない。VariantGroupごとにバリアントを1つ選び、その配下だけを畳んで出力する
- 部品グループ・スイッチの向きはKLE JSONに出力しない。sm, sb, st には取り込み時に保持した値をそのまま書き戻す
- KLEの `p` はキーキャップのプロファイル名(SA、DCSなど)であり、PHYのプロファイルとは対応させない
@@ -253,7 +302,8 @@ const kleData = (ConfigObject | KeyLabel)[][]
既存のPHYデータを畳んだ配置に対して、KLE JSONの各キーを形状(位置・サイズ・回転)とラベルで照合する。
- 照合できたキーは元のノードとして扱う。KLE側で配置が変わっていれば、元の親から見た相対座標に戻して反映する
- 照合できないキーは root 直下に新規キーとして置く。クラスターへの割り当てはユーザーが行う
- 照合できないキーは root 直下に新規キーとして置く。クラスターとバリアントへの割り当てはユーザーが行う
- 照合の対象は、出力時に選んだバリアントの配下にあるキーに限る。選ばれなかったバリアントのキーは照合にも削除にも関与しない
- 構造の復元は保証しない。KLE側での編集が大きいほど、クラスター構造は失われる
- 配列の順番は照合に使わない。KLEは保存時にキーを「角度 → rx → ry → y → x」の順に並べ替えるため、順番は形状から決まる以上の情報を持たない
@@ -266,11 +316,11 @@ Beyond KLEはスイッチの品種を持たないため、対応づける先が
## 検討済み・非採用
- スイッチのブランドをPHYで持つ (journal/2026-09-20-switch-terminal.md)
- スイッチの品種・ソケット方式をPHYで持つ (journal/2026-09-20-switch-terminal-reversal.md)
- LED専用ノード (journal/2026-09-20-led-node.md)
- per-key LEDに座標を持たせる (journal/2026-09-20-led-node.md)
- KLE取り込み時のクラスター自動推定 (journal/2026-09-20-cluster-manual-grouping.md)
- レイアウトバリアントをキーごとのタグとファイル単位の宣言で持つ (journal/2026-09-21-multi-layout.md)
## 未確認事項
@@ -317,3 +367,10 @@ Beyond KLEはスイッチの品種を持たないため、対応づける先が
- 位置づけ: 未解決の問い。数値入力以外に、原点をどこへ吸着させるか
- 現状の認識: キーのローカル原点(左上角)・キー中心・境界矩形の角と中心が候補。相対グリッドとは別の機構になる
- 格上げ条件: 原点移動を実装し、吸着なしで足りるか、足りない場合どの候補が要るかを確認する
### P-15 複数のバリアントで共通のキーをどう置くか
- 位置づけ: 未解決の問い。本文「レイアウトバリアント」は1つのキーが1つのVariantにしか属さない形になっている
- 現状の認識: 3択のうち2つで存在し1つでは存在しないキーは、今の木では表せない。同じキーを2つのVariantに
複製すると別IDになり、ELC・IDX・MAPの記述が二重になる。そもそもそういう構成が実在するかを確認していない
- 格上げ条件: 選択肢をまたいで共通のキーが要る実在の基板を探す。あれば表現方法を決める