From bb1108763a56223de97585c37c9cfc6fac2f19bd Mon Sep 17 00:00:00 2001 From: EwdErna Date: Fri, 18 Sep 2026 21:18:49 +0900 Subject: [PATCH] =?UTF-8?q?KLE=E4=BA=92=E6=8F=9B=E3=83=89=E3=82=AD?= =?UTF-8?q?=E3=83=A5=E3=83=A1=E3=83=B3=E3=83=882=E6=9C=AC=E3=82=92?= =?UTF-8?q?=E5=BB=83=E6=AD=A2=E3=81=97=E3=80=81=E8=A3=8F=E5=8F=96=E3=82=8A?= =?UTF-8?q?=E3=81=97=E3=81=9F=E4=BA=8B=E5=AE=9F=E3=82=92PHY=E3=81=AB?= =?UTF-8?q?=E6=9B=B8=E3=81=8D=E6=88=BB=E3=81=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit kle-compatibility.md / kle-compatibility-analysis.md は埋め込み前提の 設計で、KLE往復の決定と矛盾していた。KLE本家ソースで確認できた事実だけを PHYレイヤー.md に書き戻し、2本は削除した。 - ConfigObject の回転角度キーを ra から r に修正し、fa sm sb st を追加 - KLE出力で失われる情報、KLEの p がPHYのプロファイルと別物であることを明記 - KLEは保存時にキーを並べ替えるため、配列順は照合に使わない - 過去のKLE JSONはPHYデータなしでも読めなければならない、という制約を追加 - 未確認事項に P-3 クラスター自動推定、P-4 KLE固有の形状・属性の受け止め先を追加 Journal: journal/2026-09-18-kle-compat-docs-retire.md Co-Authored-By: Claude Opus 5 --- CLAUDE.md | 2 - PHYレイヤー.md | 36 +- journal/2026-09-18-kle-compat-docs-retire.md | 46 ++ kle-compatibility-analysis.md | 453 ------------------- kle-compatibility.md | 249 ---------- 5 files changed, 78 insertions(+), 708 deletions(-) create mode 100644 journal/2026-09-18-kle-compat-docs-retire.md delete mode 100644 kle-compatibility-analysis.md delete mode 100644 kle-compatibility.md diff --git a/CLAUDE.md b/CLAUDE.md index b64d9a4..f062e14 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -13,8 +13,6 @@ PHY(物理配置) / ELC(電気配線) / IDX(キー識別) / MAP(キーマップ) | `keyboard-design-layers.md` | レイヤー構造とツール分割方針(最上位) | | `PHYレイヤー.md` | PHY層の仕様 | | `phase1-json-schema.md` | 各層のJSON Schema | -| `kle-compatibility.md` | KLEとの双方向変換仕様 | -| `kle-compatibility-analysis.md` | KLE互換性の調査・案比較 | | `keyboard-making-workflow.md` | 既存の自作キーボード制作フローとの対応 | | `typescript-implementation-plan.md` | 実装計画・技術スタック | diff --git a/PHYレイヤー.md b/PHYレイヤー.md index c1ffe57..dfa5615 100644 --- a/PHYレイヤー.md +++ b/PHYレイヤー.md @@ -98,6 +98,7 @@ KLEで編集された時点で、そのデータはBeyond KLEのデータでは - KLE JSONにはBeyond KLE固有の情報(キーID、クラスター構造など)を含めない。出力は素のKLE JSONで、KLE JSONを読む他ツールにそのまま渡せる - KLE JSONの取り込みは、手元のPHYデータとの照合で行う。IDや埋め込み情報には頼らない +- 過去のKLE JSONは、PHYデータがなくても読み込めなければならない。変換を伴ってよい ### KLE JSON出力 @@ -113,9 +114,9 @@ type ConfigObject = { y2?: number, w2?: number, h2?: number, - rx?: number, + r?: number, // 回転角度 + rx?: number, // 回転中心 ry?: number, - ra?: number, l?: boolean, n?: boolean, d?: boolean, @@ -125,14 +126,22 @@ type ConfigObject = { a?: number, f?: number, f2?: number, + fa?: number[], p?: string, - s?: string + sm?: string, + sb?: string, + st?: string } type KeyLabel = string // 表示用ラベルのみ。識別情報は含めない const kleData = (ConfigObject | KeyLabel)[][] ``` +- 回転角度は正規化せずそのまま出力する。KLEのデータは任意の角度を受け付け、15度刻みはKLEのUI上の操作単位にすぎない +- rx, ry はPHYに持たないので、出力時に選ぶ +- ユニットサイズ(mm)、ビジュアルオフセット、クラスター構造はKLE JSONに出力されない +- KLEの `p` はキーキャップのプロファイル名(SA、DCSなど)であり、PHYのプロファイルとは対応させない + ### KLE JSONの取り込み 既存のPHYデータを畳んだ配置に対して、KLE JSONの各キーを形状(位置・サイズ・回転)とラベルで照合する。 @@ -140,6 +149,9 @@ const kleData = (ConfigObject | KeyLabel)[][] - 照合できたキーは元のノードとして扱う。KLE側で配置が変わっていれば、元の親から見た相対座標に戻して反映する - 照合できないキーは root 直下に新規キーとして置く。クラスターへの割り当てはユーザーが行う - 構造の復元は保証しない。KLE側での編集が大きいほど、クラスター構造は失われる +- 配列の順番は照合に使わない。KLEは保存時にキーを「角度 → rx → ry → y → x」の順に並べ替えるため、順番は形状から決まる以上の情報を持たない + +KLEの rx, ry, r はキーの絶対配置 (x, y, rotation) に変換して取り込む。元の rx, ry は保持しない。 ## 検討済み・非採用 @@ -154,10 +166,26 @@ const kleData = (ConfigObject | KeyLabel)[][] - 位置づけ: 本文が前提にしているものではない。連携用出力形式の設計に関わる未解決の問い - 現状の認識: 階層を畳んでKLEに読み込ませると行のまとまりが崩れる。他レイヤーの情報を使ってでも行ごとにまとめたいが、方法は未検討 +- 手がかり: KLEは r, rx, ry が同じで y が等しいキーを1行にまとめる。同じ絶対角度を持つキーに共通の rx, ry(例えばクラスターの原点)を選べば、行にまとめられる見込み - 格上げ条件: 回転を含むPHYデータをKLE JSONに変換してKLE本家に読み込ませ、rotation groupと行配列がどう再構成されるかを確認する ### P-2 KLE JSON取り込み時の照合基準 - 位置づけ: 本文「KLE JSONの取り込み」の具体化に必要な未解決の問い -- 現状の認識: 形状の許容誤差、ラベルの扱い、複数候補がある場合の決め方が未定。KLEが保存時にキーの並び順を変えるかは未確認で、配列順を照合に使えるかも分からない +- 現状の認識: 形状の許容誤差、ラベルの扱い、複数候補がある場合の決め方が未定 - 格上げ条件: 照合規則を決めたうえで、KLE本家でキーの移動・追加・削除をしたJSONを取り込み、意図どおりに対応づくことを確認する + +### P-3 KLE JSON取り込み時のクラスター自動推定 + +- 位置づけ: 未解決の問い。PHYデータなしで過去のKLE JSONを取り込むとき、座標の近さや角度からクラスターを推定するか +- 現状の認識: 採用しない可能性が高い。ただし代わりに欲しい機能があり、それを思い出すきっかけとして残している +- 格上げ条件: 代わりの機能を定義し、この推定を採るか捨てるかをユーザーが決める + +### P-4 KLE固有の形状と属性の受け止め先 + +- 位置づけ: 本文「過去のKLE JSONは読み込めなければならない」を満たすために必要な未解決の問い +- 現状の認識: 現在の Key 型(transform, size, profile)では次を受け止められない + - 長方形でないキー(x2, y2, w2, h2。ISO Enterなど)。受け止められないとISO配列が読めない。ローカルの値なので Size の拡張で相対座標モデルに収まる見込み + - デカールとゴースト(d, g)。PHYで持つか、取り込み時に捨てるか + - 見た目の属性(ラベル、c, t, p, f系, l, n)。落としてよいか、別の層で保持するか。ラベルは照合にも使う +- 格上げ条件: 各項目について、PHYで持つ・他の層で持つ・捨てるのいずれかをユーザーが決め、Key 型に反映する diff --git a/journal/2026-09-18-kle-compat-docs-retire.md b/journal/2026-09-18-kle-compat-docs-retire.md new file mode 100644 index 0000000..4a0bc39 --- /dev/null +++ b/journal/2026-09-18-kle-compat-docs-retire.md @@ -0,0 +1,46 @@ +# KLE互換ドキュメント2本の廃止と書き戻し + +## 結論 + +- kle-compatibility.md / kle-compatibility-analysis.md を作業ツリーから削除した + - 原本: `git show 1a9a2a0:kle-compatibility.md` / `git show 1a9a2a0:kle-compatibility-analysis.md` + - 経緯: compatibility は初期PHYドキュメントをもとに検討しながら更新したもの。analysis はそれをさらに分析したもの(ユーザー談) +- PHYレイヤー.md に書き戻したもの(KLE本家ソースで裏取り済み) + - ConfigObject の修正: `ra` → `r`、`fa` `sm` `sb` `st` を追加 + - 回転角度は正規化せず出力できる(15度はUIの操作単位) + - ユニットサイズ・ビジュアルオフセット・クラスター構造はKLEに出力されない + - KLEの `p` はキーキャップのプロファイル名で、PHYのプロファイルとは別物 + - KLEは保存時にキーを並べ替えるので、配列順は照合に使えない + - P-1 に行まとめの手がかりを追記 +- 新たに本文に加えた制約: 過去のKLE JSONはPHYデータなしでも読めなければならない(ユーザー要件。変換は可) +- 未確認事項として立てたもの: P-3 クラスター自動推定(未決。代わりに欲しい機能を思い出すきっかけ)、P-4 KLE固有の形状・属性の受け止め先 + +## 各記述の行き先 + +| 元の記述 | 行き先 | +|---|---| +| 階層を畳む flattenElements | 既にPHYにある(階層を畳んで絶対座標に変換) | +| ID保持方法の比較、`_beyondkle` ハイブリッド、ID復元 | 捨てた。2026-09-18-kle-roundtrip で不採用 | +| 往復で構造が一致することを保証するテスト | 捨てた。「構造の復元は保証しない」と矛盾 | +| ConversionSettings, バージョン管理メタデータ | 捨てた。埋め込み前提 | +| autoDetectClusters | PHY 未確認事項 P-3 | +| CLI コマンド例 (export/import) | 捨てた。CLIの形は実装計画側で決める | +| KLE Key クラスのプロパティ一覧、互換性マトリックス | 事実部分のみ ConfigObject とKLE出力の制約として書き戻し | +| 「プロファイル設定 ↔ p が1:1対応」 | 誤り。KLEの p はキャップ形状名 | +| KLE UI改造の項目・難易度・80/15/5%・フェーズ分け | 捨てた。KLE改造か自作かを検討するときは原本を git show で読む | +| ゴーストキーによる階層クラスター | 捨てた。2026-09-18-kle-roundtrip で不採用 | +| 15度回転制約の分析 | 結論のみ書き戻し。analysis 中の kb.js 引用コードは実物と一致(kb.js:817) | + +## 検証ログ + +ijprest/keyboard-layout-editor master (2026-09-18 取得) + +- serial.js:92-100 sortKeys。角度((a+360)%360) → rotation_x → rotation_y → y → x の順に並べ替える +- serial.js:187 serialize の中で sortKeys を呼ぶ。保存のたびに並べ替わる +- serial.js:193-198 行が切り替わる条件は y の変化か (r, rx, ry) の変化 +- serial.js:219-269 出力されるプロパティは r rx ry y x c t g p sm sb st a f f2 fa w h w2 h2 x2 y2 n l d で決め打ち。未知のプロパティは落ちる + - 2026-09-18-kle-roundtrip で「未確認」とした「シリアライザは既知プロパティしか書かない」はこれで確定 +- serial.js:105 defaultKeyProps で profile は "cap appearance" に分類されている +- serial.js:176-178 メタデータは keyboard.meta の全キーをループで書き出す。未知のメタデータキーも保存時に残る(今回の決定では使わない) +- kb.js:78 rotateStep = 15。kb.js:817 プロパティ入力は ±180 にクランプするだけ。kb.js:1119 キー操作による回転は Math.round で整数度に丸める +- kb.css:94 `.ghosted { opacity: 0.5; }`。ゴーストキーは半透明で表示される。analysis の「見た目に影響しない」は誤り diff --git a/kle-compatibility-analysis.md b/kle-compatibility-analysis.md deleted file mode 100644 index 6861808..0000000 --- a/kle-compatibility-analysis.md +++ /dev/null @@ -1,453 +0,0 @@ -# PHYレイヤーとKLE(Keyboard Layout Editor)の互換性分析 - -## 概要 - -検討中のPHYレイヤー構造とKeyboard Layout Editor(KLE)の互換性について詳細に分析した結果をまとめます。KLEをベースとしたフロントエンドの実現可能性を評価します。 - -## KLEデータモデルの特徴 - -### KLEで対応可能な主要プロパティ - -KLEの`Key`オブジェクトは以下の構造を持ちます: - -```typescript -export class Key { - // 位置・サイズ関連 - x: number; // 絶対位置 (U単位) - y: number; // 絶対位置 (U単位) - width: number; // サイズ (U単位) - height: number; // サイズ (U単位) - - // 回転関連 - rotation_x: number; // 回転中心X座標 - rotation_y: number; // 回転中心Y座標 - rotation_angle: number; // 回転角度 - - // 複雑な形状対応 - x2: number; // 第2矩形の相対位置 - y2: number; // 第2矩形の相対位置 - width2: number; // 第2矩形のサイズ - height2: number; // 第2矩形のサイズ - - // 表示・装飾関連 - color: string; // キーキャップ色 - labels: string[]; // 最大12個のラベル - textColor: Array; - textSize: Array; - profile: string; // キープロファイル - - // フラグ類 - decal: boolean; // デカールモード - ghost: boolean; // ゴーストモード - stepped: boolean; // ステップキー - nub: boolean; // ホーミング突起 - - // スイッチ情報 - sm: string; // スイッチマウント - sb: string; // スイッチブランド - st: string; // スイッチタイプ -} -``` - -## 互換性マトリックス - -### ✅ 完全対応可能 - -| PHYレイヤー機能 | KLEプロパティ | 備考 | -|---|---|---| -| キー座標(x,y) | `x`, `y` | 1:1対応、U単位 | -| キーサイズ(w,h) | `width`, `height` | 1:1対応、U単位 | -| 回転角度 | `rotation_angle` | 1:1対応 | -| 回転中心 | `rotation_x`, `rotation_y` | 1:1対応 | -| 0.25U単位スナップ | - | KLEも小数点座標対応 | -| 複雑形状キー | `x2`, `y2`, `width2`, `height2` | ISO Enter等に対応 | -| プロファイル設定 | `profile` | SA、DCS、OEM等対応 | - -### ⚠️ 部分対応・要改造 - -| PHYレイヤー機能 | KLE対応状況 | 改造内容 | -|---|---|---| -| クラスター管理 | 非対応 | カスタムメタデータとしてlabelsに格納 | -| 複数プロファイル | 一部対応 | メタデータで管理、UI拡張必要 | -| ユニットサイズ設定 | 非対応 | グローバル設定として追加実装 | -| ビジュアルオフセット | 非対応 | レンダリング層で独自実装 | - -### ❌ 対応困難・KLE制約 - -| PHYレイヤー機能 | KLE制約 | 回避策 | -|---|---|---| -| 15度以外の回転角度 | UI制約(内部は対応可能) | UI改造またはAPI直接操作 | -| 階層的クラスター | データモデル非対応 | ゴーストキーによるメタデータ保存 | -| クラスター別回転中心 | 直接非対応 | 各キーの回転中心で代替 | - -## 具体的な実装戦略 - -### 1. KLEベースデータ変換 - -PHYレイヤーからKLE形式への変換: - -```typescript -// PHYレイヤー → KLE変換例 -function convertToKLE(phyData: PHYLayer): KLEData { - return phyData.elements.map(element => { - if (element.type === 'key') { - return { - x: element.position.x, - y: element.position.y, - width: element.size.width, - height: element.size.height, - rotation_x: element.position.rotationOrigin?.x || 0, - rotation_y: element.position.rotationOrigin?.y || 0, - rotation_angle: element.position.rotation || 0, - // クラスター情報をlabelsの特定位置に格納 - labels: [element.clusterId || '', '', '', '', '', '', '', '', '', '', '', ''], - // プロファイル情報 - profile: element.profile || 'OEM' - }; - } - // クラスターの場合は展開処理 - }); -} -``` - -### 2. KLE UI改造点 - -#### 必要な改造項目 - -1. **クラスター管理UI** - - クラスター作成・編集パネル - - クラスター単位の選択・移動 - - クラスター階層表示 - -2. **プロファイル管理** - - 複数プロファイル切り替えUI - - プロファイル別ユニットサイズ設定 - -3. **メタデータ拡張** - - PHYレイヤー固有情報の保存 - - 互換性情報の管理 - -#### UI改造の難易度 - -- **低難易度**: 既存プロパティパネルの拡張 -- **中難易度**: クラスター管理機能の追加 -- **高難易度**: レンダリングエンジンの改造 - -### 3. 制限事項と回避策 - -#### 現在のKLE制約 - -1. **データモデル制約** - - フラットな配列構造のみ対応 - - 階層的クラスター管理は困難 - -2. **レンダリング制約** - - HTMLベースのレンダリング - - 複雑な視覚効果には限界 - -#### 回避策 - -1. **段階的対応** - - Phase 1: 基本的な位置・サイズ・回転のみ対応 - - Phase 2: クラスター管理機能追加 - - Phase 3: 高度なビジュアル機能 - -2. **ハイブリッドアプローチ** - - KLEをベースエディタとして使用 - - 独自機能は別パネルで管理 - - 最終出力時にPHYレイヤー形式で統合 - -## 推奨実装アプローチ - -### フェーズ1: KLE最小改造アプローチ(推奨) - -1. **KLEの既存機能をそのまま活用** - - 基本的な配置・サイズ・回転 - - プロファイル設定 - - 色・ラベル設定 - -2. **最小限の拡張** - - カスタムメタデータ保存機能 - - PHYレイヤー形式エクスポート - -3. **段階的機能追加** - - クラスター管理(Phase 2) - - 高度なビジュアル機能(Phase 3) - -### 実装優先順位 - -1. **高優先度** - 即座に対応可能 - - ✅ 基本位置・サイズ・回転 - - ✅ プロファイル設定 - - ✅ KLE→PHYレイヤー変換 - -2. **中優先度** - 改造が必要だが実現可能 - - ⚠️ 簡易クラスター管理 - - ⚠️ 複数プロファイル対応 - - ⚠️ カスタムユニットサイズ - -3. **低優先度** - 大規模改造が必要 - - ❌ 階層的クラスター - - ❌ 高度なビジュアルオフセット - - ❌ リアルタイム3Dプレビュー - -## 結論 - -**KLEをベースとしたPHYレイヤーエディタの実現は十分可能**です。 - -### 対応可能な機能(約80%) - -- 基本的なキー配置・サイズ・回転 -- 複雑形状キー(ISO Enter等) -- プロファイル管理 -- 基本的なクラスター管理 - -### 改造が必要な機能(約15%) - -- 高度なクラスター管理 -- 複数プロファイル切り替え -- カスタムユニットサイズ - -### 対応困難な機能(約5%) - -- 完全階層的クラスター構造 -- 高度なビジュアルエフェクト - -PHYレイヤーの主要機能はKLEで十分実現可能であり、段階的な改造により完全対応も期待できます。 - -## 階層型クラスターの実装戦略 - -### 問題提起 - -ユーザーからの要求: - -- **階層型クラスター管理は絶対に実装したい** -- 出力時はフラット化してもOK(階層情報を何らかの形で記録できれば) -- ラベルに突っ込むと見づらくなる懸念 -- **ゴーストキーによる情報保存**のアイデア - -### ゴーストキーアプローチの詳細設計 - -#### 基本概念 - -クラスター情報を`ghost: true`のキーとして保存し、実際のキーレンダリングには影響を与えずにメタデータとして扱う。 - -```typescript -// クラスター情報保存用ゴーストキー -type ClusterGhostKey = { - ghost: true, - decal: false, - x: number, // クラスター範囲の左上角 - y: number, // クラスター範囲の左上角 - width: number, // クラスター範囲の幅 - height: number, // クラスター範囲の高さ - rotation_x: number, // クラスター回転中心 - rotation_y: number, // クラスター回転中心 - rotation_angle: number, // クラスター回転角度 - color: "#transparent", // 透明 - labels: [ - "CLUSTER_META", // [0] 識別子 - clusterId, // [1] クラスターID - parentClusterId, // [2] 親クラスターID(階層用) - clusterName, // [3] クラスター名 - JSON.stringify(metadata), // [4] その他メタデータ - "", "", "", "", "", "", "" // [5-11] 予約 - ] -} -``` - -#### 階層構造の表現 - -```typescript -// 例:分割キーボードの左右ブロック + 各ブロック内のキークラスター -const clusterHierarchy = { - "root": { - children: ["left_block", "right_block"] - }, - "left_block": { - parent: "root", - children: ["left_alpha", "left_modifiers"] - }, - "right_block": { - parent: "root", - children: ["right_alpha", "right_modifiers"] - }, - "left_alpha": { - parent: "left_block", - keyIds: ["Q", "W", "E", "R", "T", "A", "S", "D", "F", "G", ...] - } - // ... -} -``` - -#### KLE UI拡張による階層管理 - -1. **クラスター管理パネル** - - ```html - -
- - - - - - - - - - - - -
- ``` - -2. **クラスター操作機能** - - ドラッグ&ドロップによるキーのクラスター移動 - - 階層ツリーでのクラスター選択 - - クラスター単位での一括変換(移動・回転・リサイズ) - - クラスター単位でのコピー&ペースト - -### データフロー設計 - -#### 1. 編集時(UI → 内部データ) - -```javascript -// クラスター作成時 -function createCluster(name, parentId, selectedKeys) { - const clusterId = generateUniqueId(); - - // ゴーストキーを作成 - const ghostKey = createClusterGhostKey({ - id: clusterId, - name: name, - parentId: parentId, - boundingBox: calculateBoundingBox(selectedKeys) - }); - - // 選択されたキーにクラスターIDを付与 - selectedKeys.forEach(key => { - key.clusterId = clusterId; // カスタムプロパティとして追加 - }); - - // KLEのキー配列に追加 - scope.keys().push(ghostKey); -} -``` - -#### 2. 保存時(内部データ → KLE JSON) - -```javascript -function serializeWithClusters(keyboard) { - const kleData = serial.serialize(keyboard); - - // 通常のキーとゴーストキーが混在した状態で保存 - // ゴーストキーがクラスター情報を保持 - return kleData; -} -``` - -#### 3. 読み込み時(KLE JSON → 内部データ) - -```javascript -function deserializeWithClusters(kleData) { - const keyboard = serial.deserialize(kleData); - - // ゴーストキーからクラスター情報を復元 - const clusterMap = new Map(); - const normalKeys = []; - - keyboard.keys.forEach(key => { - if (key.ghost && key.labels[0] === 'CLUSTER_META') { - const clusterId = key.labels[1]; - const parentId = key.labels[2]; - const metadata = JSON.parse(key.labels[4]); - - clusterMap.set(clusterId, { - ghostKey: key, - parentId: parentId, - metadata: metadata, - children: new Set() - }); - } else { - normalKeys.push(key); - } - }); - - // 階層構造を再構築 - buildClusterHierarchy(clusterMap); - - return { keyboard: { ...keyboard, keys: normalKeys }, clusters: clusterMap }; -} -``` - -### 15度回転制約について - -#### 現在の制約の詳細 - -KLEのソースコード分析結果: - -```javascript -$scope.rotateStep = 15; // UI上のデフォルト回転ステップ - -// 実際の制約チェック(kb.js内) -rotation_angle: function() { - return Math.max(-180, Math.min(180, value)); // ±180度の範囲制約のみ -} -``` - -**つまり:** - -- **UIでは15度ステップで回転操作**(ユーザビリティのため) -- **内部データには制約なし**(任意の角度を保存可能) -- **JSON出力も制約なし**(小数点を含む任意の角度値) - -#### PHYレイヤーでの対応 - -```javascript -// PHY → KLE変換時に任意角度をそのまま渡す -function convertRotation(phyRotation) { - return phyRotation; // 制約なし、そのまま変換 -} - -// KLE UI拡張で任意角度入力を許可 -function enableCustomRotation() { - // 既存の15度ステップに加えて、直接入力機能を追加 - scope.customRotateStep = 1; // 1度ステップ - scope.allowCustomAngle = true; // 任意角度入力許可 -} -``` - -## 実装優先度の再評価 - -### 修正版優先度 - -1. **最高優先度** - 即座に対応可能 - - ✅ 基本位置・サイズ・回転(任意角度対応) - - ✅ プロファイル設定 - - ✅ KLE→PHYレイヤー変換 - -2. **高優先度** - ゴーストキーアプローチで対応 - - 🔶 階層型クラスター管理(ゴーストキー方式) - - 🔶 クラスターメタデータ保存 - - 🔶 クラスター単位操作UI - -3. **中優先度** - UI改造が必要 - - ⚠️ 複数プロファイル対応 - - ⚠️ カスタムユニットサイズ - - ⚠️ 15度以外の回転角度UI対応 - -4. **低優先度** - 大規模改造が必要 - - ❌ 高度なビジュアルオフセット - - ❌ リアルタイム3Dプレビュー - -### 実装結論 - -**ゴーストキーアプローチにより、階層型クラスター管理は実現可能**です。この方法なら: - -- KLEの既存データモデルを活用 -- 見た目に影響しない形でメタデータ保存 -- 階層構造の完全な再現が可能 -- 段階的な実装が可能 - -階層型クラスターが「絶対実装したい」要求に対して、技術的に実現可能な解決策を提供できます。 diff --git a/kle-compatibility.md b/kle-compatibility.md deleted file mode 100644 index 48423fc..0000000 --- a/kle-compatibility.md +++ /dev/null @@ -1,249 +0,0 @@ -# KLE JSON 互換性設計 - -## 双方向変換戦略 - -### Beyond KLE → KLE JSON - -#### 1. フラット化プロセス - -```typescript -interface ConversionOptions { - preserveIds: boolean; // IDを保持するか - preserveClusterInfo: boolean; // クラスター情報を保持するか - idEmbedMethod: 'metadata' | 'label' | 'comment'; -} - -function convertToKLE(beyondKle: PHYLayer, options: ConversionOptions): KLELayout { - const flatKeys = flattenElements(beyondKle.elements); - return { - name: beyondKle.metadata.name, - keys: flatKeys.map(key => convertKey(key, options)) - }; -} - -function flattenElements(elements: Element[], parentTransform?: Transform): FlatKey[] { - const result: FlatKey[] = []; - - for (const element of elements) { - if (element.type === 'key') { - const absolutePos = applyTransform(element.position, parentTransform); - result.push({ - ...element, - absolutePosition: absolutePos, - clusterPath: getClusterPath(element) - }); - } else if (element.type === 'cluster') { - const clusterTransform = combineTransforms(parentTransform, element.position); - result.push(...flattenElements(element.elements, clusterTransform)); - } - } - - return result; -} -``` - -#### 2. ID保持方法の比較 - -| 方法 | メリット | デメリット | KLE互換性 | -|------|----------|------------|-----------| -| `_beyondkle` メタデータ | 構造化された情報保持 | KLEパーサーが無視する可能性 | △ | -| ラベル9番目位置 | 確実に保存される | 表示されてしまう | ○ | -| コメントフィールド | 非表示 | 標準的でない | △ | - -#### 3. 推奨アプローチ: ハイブリッド方式 - -```json -{ - "name": "Split Layout (Generated by Beyond KLE)", - "_beyondkle": { - "version": "1.0.0", - "sourceFile": "layout.beyond.json", - "conversionSettings": { - "flattenClusters": true, - "preserveRotations": true - } - }, - "keys": [ - { - "x": 0, "y": 0, "w": 1, "h": 1, - "t": "#000000\n\n\n\n\n\n\n\n\nk00", - "_beyondkle": { - "id": "k00", - "clusterPath": ["left_half", "left_main"], - "relativePosition": { "x": 0, "y": 0 }, - "absolutePosition": { "x": 0, "y": 0 } - } - } - ] -} -``` - -### KLE JSON → Beyond KLE - -#### 1. ID復元戦略 - -```typescript -function convertFromKLE(kleLayout: KLELayout): PHYLayer { - // 1. メタデータからBeyond KLE情報を取得 - const beyondKleInfo = kleLayout._beyondkle; - - if (beyondKleInfo?.sourceFile) { - // 元のBeyond KLEファイルが指定されている場合 - return reconstructFromSource(kleLayout, beyondKleInfo); - } - - // 2. キーからIDとクラスター情報を抽出 - const keys = kleLayout.keys.map(kleKey => { - const id = extractId(kleKey); - const clusterInfo = extractClusterInfo(kleKey); - - return { - type: 'key' as const, - id: id || generateId(kleKey), - profile: 'default', - position: { x: kleKey.x, y: kleKey.y }, - size: { width: kleKey.w || 1, height: kleKey.h || 1 }, - metadata: extractMetadata(kleKey) - }; - }); - - // 3. クラスター構造の再構築 - return reconstructClusters(keys); -} - -function extractId(kleKey: any): string | null { - // 1. _beyondkle メタデータから - if (kleKey._beyondkle?.id) return kleKey._beyondkle.id; - - // 2. ラベル9番目から - if (kleKey.labels?.[8]) return kleKey.labels[8]; - - // 3. t文字列の解析 - const tMatch = kleKey.t?.match(/\n([a-zA-Z0-9_]+)$/); - if (tMatch) return tMatch[1]; - - return null; -} -``` - -#### 2. クラスター再構築アルゴリズム - -```typescript -function reconstructClusters(flatKeys: Key[]): Element[] { - // クラスター情報が保持されている場合 - const clusteredKeys = groupByCluster(flatKeys); - - if (Object.keys(clusteredKeys).length > 1) { - return Object.entries(clusteredKeys).map(([clusterName, keys]) => ({ - type: 'cluster' as const, - id: clusterName, - name: clusterName, - position: calculateClusterOrigin(keys), - elements: keys.map(key => ({ - ...key, - position: makeRelativeToCluster(key.position, clusterOrigin) - })) - })); - } - - // クラスター情報がない場合は自動推定 - return autoDetectClusters(flatKeys); -} - -function autoDetectClusters(keys: Key[]): Element[] { - // 座標の近さとレイアウトパターンからクラスターを推定 - // 1. 連続する矩形領域の検出 - // 2. 回転角度の類似性 - // 3. 一定の間隔での分離 - - const clusters = detectSpatialClusters(keys); - - if (clusters.length === 1) { - // 単一クラスターの場合はフラットに - return keys; - } - - return clusters; -} -``` - -## 実装における考慮事項 - -### 1. バージョン管理 - -```json -{ - "_beyondkle": { - "version": "1.0.0", - "generator": "beyond-kle-converter", - "timestamp": "2025-11-09T12:00:00Z", - "preservedData": { - "clusters": true, - "rotations": true, - "profiles": false - } - } -} -``` - -### 2. 設定可能な変換オプション - -```typescript -interface ConversionSettings { - // ID保持方法 - idPreservation: 'metadata' | 'label' | 'both' | 'none'; - - // クラスター処理 - clusterHandling: 'preserve' | 'flatten' | 'auto'; - - // 回転の処理 - rotationHandling: 'preserve' | 'flatten'; - - // プロファイル情報 - includeProfiles: boolean; - - // 互換性レベル - compatibilityLevel: 'strict' | 'extended' | 'beyondkle'; -} -``` - -### 3. 往復変換の整合性保証 - -```typescript -// テストケース -const originalBeyondKLE = loadBeyondKLE('test.beyond.json'); -const kleJson = convertToKLE(originalBeyondKLE, settings); -const reconstructed = convertFromKLE(kleJson); - -// 構造的等価性の検証 -assert(structurallyEquivalent(originalBeyondKLE, reconstructed)); -``` - -## ワークフロー例 - -### 1. Beyond KLE → 外部ツール → Beyond KLE - -```bash -# Beyond KLE → KLE JSON (ID付き) -beyond-kle export --format=kle --preserve-ids layout.beyond.json - -# 外部ツール(KLE等)で編集 -# ... - -# KLE JSON → Beyond KLE (構造復元) -beyond-kle import --format=kle --auto-cluster edited.kle.json -``` - -### 2. 段階的移行 - -```bash -# 既存のKLE JSON → Beyond KLE -beyond-kle import legacy.kle.json - -# Beyond KLE で編集・管理 - -# 必要に応じてKLE JSONで共有 -beyond-kle export --format=kle-compatible project.beyond.json -``` - -この設計により、Beyond KLEの高度な機能を使いながらも、既存のKLEエコシステムとの互換性を保てると思いますが、いかがでしょうか?