コンテンツにスキップ

9. コンポーネント、編集、複数建築

def はスロット保持型 Component を定義し、theme および site と同じ機構で統一されています。これに より参照系が、編集・テーマ化・複数建築接続のあいだで分裂しません。

  • パラメータ化 (可変サイズなど) は許可します。再帰は禁止です。
  • defrequires version>=X を宣言してかまいません。コンポジットの最小バージョンはその構成要素 の最大値です (バージョンとエディション)。
def cottage class=house size=9x7:
floor id=floor mat_slot=floor
walls id=walls class=outer mat_slot=wall height=4
door id=door class=entry side=front at=center
roof id=roof kind=gable mat_slot=roof

明示 ID + 自動安定アドレスの組み合わせ。重要なメンバは id= を持ち、未指定のメンバはコンパイラが 意味ベースの安定アドレス を自動付与します。アドレスは生成順ではなく parent / role / side / level / offset から導かれるため、追記しても安定します。

編集はセレクタ/アドレスに対するパッチ DSL です:

edit window[class=vent][level=floor2] set shape=arch
edit window@front[0] set mat_slot=accent_glass
edit door[id=entry] set side=front at=center

「2階の窓だけアーチにする」のような概念レベルの編集が、全体を壊さずに行える必要があります。編集 diff は intent_state のみを見るため (ブロックステート)、導出結果の変化は編集の安定 性を損ないません。

AI に絶対座標の計算をさせない。トポロジカルな関係制約で配置し、絶対座標への解決はコンパイラの責務 とします。

site village:
place id=home1 use=cottage theme=medieval at=origin
place id=home2 use=cottage theme=medieval east_of=home1 gap=4
connect home1.door to home2.door path=@gravel

各 struct はポート (位置 / 法線 / 幅) を露出し、connect がそれらを繋ぎます。structure block の 48³ 上限を超える村や城は、複数 struct の合成で表現します。

  • east+x 方向、north-z 方向に進みます。これは §5.4 の front+z の規約と整合し ます — 南を向く建築の正面は +z 側にあり、north_of=X は次の配置をその背後に置きます。
  • Y 軸はトポロジカルセレクタの影響を受けません。現状すべての配置は y = 0 です。

placeat / east_of / north_ofちょうど 1 つ を持ちます:

セレクタ効果注記
at=originワールド (0, 0, 0) に配置を固定。at= の唯一の合法値です。site 内の最初の place はこのアンカーを必須とします — at=origin の暗黙のデフォルトはありません。
east_of=ID gap=N新規 origin = 直前 (x + dims.x + N, y, z)ID は同じ site 本体で先に宣言された place 名でなければなりません。gap はブロック単位の辺間距離 (0 → 壁面が接触)。省略時は 0
north_of=ID gap=N新規 origin = 直前 (x, y, z − dims.z − N)IDgap の規則は east_of と同じ。

セレクタの併用 (at + east_ofeast_of + north_of など) は E_INVALID_PLACE_ORIGIN で拒否し ます。at=origin 以外を渡した場合も同じエラーです。

  • use=NAME はトップレベルの def を指す必要があります。未知名は E_UNRESOLVED_PLACE_REF で 失敗し、編集距離キャップに収まる候補があれば近接マッチを提示します (versioning-editions.md §10.6 の規約に従う)。
  • theme=NAME は同一ファイルで宣言された theme を指す必要があります。未知名は E_UNRESOLVED_THEME_REF で失敗し、同様に近接マッチを伴います。
  • どの place use=NAME からも参照されない defW_UNUSED_DEF (警告) として通知されます。 use= 側のタイポが空ビルドを密かに生む事故を防ぐためです。
  • 同一 site 内で 2 つの placeid= を共有することはできません。重複は E_DUPLICATE_PLACE_ID で報告され、診断は最初の宣言へのスパンポインタを伴います。

コンパイラは place ごとに 1 ファイルの .nbt を、id= 名で書き出します (例: home1.nbthome2.nbt)。各配置のワールド座標原点と (site, def, theme) の出自は build.cairn.lockplacements セクションに記録され、下流の consumer は座標ソルバを再実行せずにレイアウトを 再構築できます。

connect FROM.PORT to TO.PORT path=@MATERIAL 行は、同一 site 内の 2 つの placement が公開する ポート間に幅 1 ブロックの歩道を敷設します。

ポート: PLACE.PORT(place, member_id) の組に解決されます。ポートを公開できるのは 参照先 defdoor メンバーと window メンバーで、stair / roof のポートは将来拡張用に 予約されています。ポートのワールド座標は「メンバーの side= 壁の外側 1 ブロック、placement の 地面段 (place_origin.1)」とし、front/back/left/right はそれぞれ +z/-z/-x/+x に対応します (§9.3.1)。壁ローカル オフセットは door ではその at= 値 (center / left / right のいずれか — §5.4 参照)、window では矩形の幾何中心 (offset + size.w / 2) を採用し、 いずれの場合も placement の overhang ぶんだけ外側にシフトして、ポートは構造外面を超えた overhang リング上に着地します。door の数値オフセット (at=N) は将来拡張用に予約されています。 window は水平方向 (offset + size.w ≤ wall_length) と垂直方向 (y + size.h ≤ walls.height) の両方で壁内に収まる必要があり、openings パスがカットを deferred 化する window はポートも構築されず、行は W_DEFERRED_MEMBER で破棄され、ノートには door / window / 予約ロールの契約が順番に列挙されます。windowy= はポートを地面段から 持ち上げません — 歩道は 1 voxel 厚の平坦な strip であり、相手側エンドポイントと Y が一致して いる必要があるためです。sym=true の window はプライマリ offset 側の中央 1 点だけがポート として参照されます (壁面上の鏡像カットは描画されますが、id= は単一の座標に解決されます)。

経路: 歩道は 2 つのポートで一致する Y で Manhattan L (先に x 軸、次に z 軸) を走ります。 階段や複数階層をまたぐ 3D 経路探索はポート面を一度に着地させるため意図的にスコープから外して います。既存の構造床と重なるセルはスキップし、行ごとに W_WALKWAY_BLOCKED を 1 件だけ警告として 発します。警告には --format json 出力で機械可読ペイロード (data: { kind: "walkway_blocked", skipped: N }) が付与され、LSP のクイックフィックスや CI アノテーターが人間向けメッセージを再パースせずにスキップ件数を読み取れます — 詳細は spec/lint.md §11.2 を参照。

マテリアル: path=@TOKEN の値はメンバーマテリアルと同じ mat_slot= パイプラインを通って解決 されます。@gravel のような canonical token はレジストリパック無しで利用でき、@path.gravel の ような abstract token はパックのマテリアルカタログを要求し、ヒットしないときは W_ABSTRACT_TOKEN_DEFERRED / E_UNKNOWN_ABSTRACT_TOKEN を発火します。

出力: 各 connect 行は site とポート名を組み合わせた 1 つの .nbt を書き出し (例: hamlet_walkway_home1_entry__home2_entry.nbt)、walkways: セクションとして lockfile に ワールド原点 / 寸法 / 解決済みパスマテリアルを記録します。

Diagnostics:

  • E_UNRESOLVED_PORT — ドット右側のポート ID が参照先 def のメンバーに存在しない (近接候補が あれば did you mean ノートを付与)。
  • E_AMBIGUOUS_PORT — def が同名 id= を複数のメンバーで公開している。重複を解消して参照を 一意にする必要があります。
  • E_MISSING_PATH_MATERIALpath= が欠落しており歩道に敷くマテリアルが無い。
  • E_UNRESOLVED_PLACE_REF — ドット左側の place ID が同一 site の先行 place を指していない。 §9.3.3 と共有のコードです。
  • W_WALKWAY_BLOCKED — L 字経路が既存の構造床を貫通した。衝突セルはスキップされ、残りの経路は そのまま敷設されます。JSON ペイロードはスキップ件数を data.skipped として公開するため、 ツール側はメッセージ本文を再パースする必要がありません。
  • W_DUPLICATE_WALKWAY — 同じ (from, to) ポート組が同一 site で既に敷設済み。重複行は破棄 されます。