ルール策定前に書かれた設計ドキュメント7点を、以降の基準点として そのままの状態で記録する。CLAUDE.md のルール1〜4は未適用。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MdLT5x5ka5y6CaWLeE3EKb
250 lines
6.5 KiB
Markdown
250 lines
6.5 KiB
Markdown
# 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エコシステムとの互換性を保てると思いますが、いかがでしょうか?
|