Files
Beyond-KLE/kle-compatibility.md
T
ewdernaandClaude Opus 5 55243f626d 初期検討段階のドキュメントと運用ルールを取り込む
ルール策定前に書かれた設計ドキュメント7点を、以降の基準点として
そのままの状態で記録する。CLAUDE.md のルール1〜4は未適用。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MdLT5x5ka5y6CaWLeE3EKb
2026-09-18 08:43:01 +09:00

6.5 KiB

KLE JSON 互換性設計

双方向変換戦略

Beyond KLE → KLE JSON

1. フラット化プロセス

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. 推奨アプローチ: ハイブリッド方式

{
  "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復元戦略

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. クラスター再構築アルゴリズム

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. バージョン管理

{
  "_beyondkle": {
    "version": "1.0.0",
    "generator": "beyond-kle-converter",
    "timestamp": "2025-11-09T12:00:00Z",
    "preservedData": {
      "clusters": true,
      "rotations": true,
      "profiles": false
    }
  }
}

2. 設定可能な変換オプション

interface ConversionSettings {
  // ID保持方法
  idPreservation: 'metadata' | 'label' | 'both' | 'none';
  
  // クラスター処理
  clusterHandling: 'preserve' | 'flatten' | 'auto';
  
  // 回転の処理
  rotationHandling: 'preserve' | 'flatten';
  
  // プロファイル情報
  includeProfiles: boolean;
  
  // 互換性レベル
  compatibilityLevel: 'strict' | 'extended' | 'beyondkle';
}

3. 往復変換の整合性保証

// テストケース
const originalBeyondKLE = loadBeyondKLE('test.beyond.json');
const kleJson = convertToKLE(originalBeyondKLE, settings);
const reconstructed = convertFromKLE(kleJson);

// 構造的等価性の検証
assert(structurallyEquivalent(originalBeyondKLE, reconstructed));

ワークフロー例

1. Beyond KLE → 外部ツール → Beyond KLE

# 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. 段階的移行

# 既存の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エコシステムとの互換性を保てると思いますが、いかがでしょうか?