ろれさんの一条工務店攻略日記

間取り図PDFをAIに渡すだけで自分の家を3D化する手順書|Claude Code / Codex用

一条工務店の紹介をろれさんに依頼する 紹介実績10人突破・入力3分・契約の義務なし 最大35万円相当のオプションが無料 →

自分の家の間取り図を、ブラウザでぐるぐる回せる3Dモデルにしてみませんか。

しかも、あなたがやることは実質3ステップだけ。図面のPDFを用意して、AIを起動して、この記事のURLを渡す。それだけです。

実際に私の家(一条工務店 GRAND SMART 平屋)でやってみたところ、間取りはもちろん、招き屋根の形・ハイドロテクトタイルの黒い外壁・太陽光パネル・大開口の窓まで、図面どおりの3Dが出来上がりました。

図面から生成した3Dモデルの南側外観。ハイドロテクトタイル黒の外壁、太陽光一体の招き屋根、大開口スライディングとウッドデッキ

図面PDFだけで生成した3Dモデル(南面)。招き屋根・黒いタイル外壁・大開口の窓・ウッドデッキまで再現されています


📖 この記事の使い方(人間が読むのはここだけ)

正直に言うと、この記事の本体は人間向けに書かれていません。AI(Claude Code / Codex)がそのまま読んで実行するための手順書です。

なので、あなたが読むのはこのセクションだけで大丈夫です。

用意するもの

必要なもの説明
間取り図のPDF一条工務店の契約者なら、貸与タブレットの図面アプリから書き出せます。平面図・立面図・電気図面があると精度が上がります
Claude Code または CodexAIにパソコンを操作してもらうためのツール。どちらか片方でOK
パソコンMac / Windows / Linux どれでも。3Dが動く程度のスペックがあれば十分

プログラミングの知識、有料の3Dソフト、CADの経験、どれもいりません。

やること(3ステップ)

1. 図面PDFを手元に置く

一条工務店のタブレットから図面PDFを書き出して、パソコンのわかりやすい場所(デスクトップなど)に保存します。ファイル名は 図面.pdf のように日本語でも大丈夫です。

2. Claude Code または Codex を起動する

ターミナル(Macなら「ターミナル」アプリ、Windowsなら「PowerShell」)を開いて、AIを起動します。

3. AIに「この記事を読んで」と伝える

起動したAIに、次のようにお願いするだけです。

https://roresan.com/blog/floorplan-3d-ai/ この記事を読んで、
その手順どおりに私の家の3Dモデルを作ってください。

図面PDFはここにあります: ~/Desktop/図面.pdf

あとはAIが、3Dエディタのダウンロードから、図面の読み取り、3Dデータの生成、ブラウザでの表示確認まで全部やってくれます。所要時間は1〜2時間くらいです。

できあがるもの

  • ブラウザでぐるぐる回せる自分の家の3Dモデル
  • 部屋の中を歩き回れるウォークスルー表示
  • 共有できるJSONファイル(家族や友人に渡せます)
  • GLB形式の3Dモデル(動画制作やBlenderにも持ち込めます)

つまずいたときは

AIが途中で失敗したら、そのエラーメッセージをそのままAIに見せて「この記事の『よくある失敗と対処』を見て直して」と伝えてください。想定される失敗パターンと対処法も記事内に書いてあるので、AIが自力で復旧できます。


以下は AI向けの手順書 です。人間が読む必要はありませんが、興味があれば折りたたみを開いてみてください。


🤖 AI向け完全手順書

AIへの指示: あなたはこれから、ユーザーの家の間取り図PDFを読み取り、Webブラウザで動作する3Dモデルを生成します。以下のセクションを 上から順に 実行してください。各セクションの折りたたみ(details)の中身がすべて実行内容です。省略・要約せずに読んでください。

成果物: ~/Documents/floorplan-3d/ 配下に生成スクリプトとシーンJSON、~/Documents/pascal-editor/ に3Dエディタ本体。

前提の確認: 作業開始前に node --version(v20以上)と python3 --version(3.9以上)を確認し、Bun未導入なら Step 1 でインストールしてください。

Step 0. 全体像とゴール設定

AIはここを開いて読む: 作業の全体設計

このタスクの本質

間取り図PDF → 3Dモデルの変換は、画像解析AIに丸投げするのではなく、「図面を人間と同じように読んで、座標テーブルに転記し、コードで3Dシーンを生成する」 というアプローチを取ります。理由は次のとおりです。

  • 日本の住宅図面(特に一条工務店)は910mmモジュールのグリッドに完全に乗っている。グリッド番号を数えるだけで座標が確定するため、画像から寸法を推定するより圧倒的に正確
  • 既存のAI自動変換ツール(FloorplanToBlender3d、CubiCasa5K等)は欧米の間取りで学習されており、日本の図面記号・尺モジュールでの精度が低い
  • 生成スクリプトを経由することで、後から一部だけ修正・再生成が容易になる

使用ツール

ツール用途ライセンス
pascalorg/editorReact Three Fiber + WebGPU製の3D建築エディタ。壁・床・屋根・建具・家具をJSONで定義できるMIT
Bunpascal-editorのビルド・実行MIT
Python 3シーンJSON生成スクリプトPSF
pdftoppm (poppler)PDFを高解像度PNG化GPL

作業フロー

図面PDF
  ↓ ① pdftoppmで200dpi PNG化 + 4分割クロップ
図面画像(精読可能な解像度)
  ↓ ② グリッド番号で壁・建具・部屋を座標テーブルに転記
座標テーブル(Pythonコード内)
  ↓ ③ generate_scene.py 実行
シーンJSON({nodes, rootNodeIds}形式)
  ↓ ④ pascal-editorにLoad Build
ブラウザ3Dモデル
  ↓ ⑤ 2D/3D表示を図面と突き合わせて差分修正(2〜3周)
完成

品質基準(これを満たすまで完成としない)

  1. 全部屋の位置・広さが平面図と一致(帖数の検算が合う)
  2. 全開口部(窓・ドア)が図面の位置・サイズと一致
  3. 屋根形状が立面図4面すべてと一致
  4. 外装の色・素材が立面図(カラー)と一致
  5. 図面に描かれている設備(キッチン・浴槽・トイレ等)が配置されている

Step 1. 環境構築

AIはここを開いて読む: ツールのインストールと起動

1-1. 必要なコマンドの確認とインストール

# バージョン確認
node --version    # v20以上が必要
python3 --version # 3.9以上が必要
bun --version     # 未インストールなら次のコマンド

Bunが未インストールの場合:

# macOS / Linux
curl -fsSL https://bun.sh/install | bash

# Windows (PowerShell)
powershell -c "irm bun.sh/install.ps1 | iex"

pdftoppm(poppler)が未インストールの場合:

# macOS
brew install poppler

# Ubuntu / Debian
sudo apt install poppler-utils

# Windows: https://github.com/oschwartz10612/poppler-windows/releases からダウンロード

1-2. 3Dエディタのクローンとセットアップ

重要: ユーザーのプロジェクトリポジトリの 外側 にクローンしてください。中に置くとgitが入れ子になります。

cd ~/Documents
git clone --depth 1 https://github.com/pascalorg/editor.git pascal-editor
cd pascal-editor
bun install    # 数分かかる。node_modulesは1GB超になる

1-3. 開発サーバー起動

cd ~/Documents/pascal-editor
bun run dev    # → http://localhost:3002 で起動

バックグラウンド実行し、curl -s -o /dev/null -w "%{http_code}" http://localhost:3002 が200を返すまで待機してください。

1-4. 作業ディレクトリの作成

mkdir -p ~/Documents/floorplan-3d

つまずきポイント

  • bun install が失敗する場合、Node v20未満の可能性。nodebrew/nvm等でv20以上に切り替える
  • ポート3002が使用中なら lsof -ti:3002 | xargs kill -9 で解放
  • WebGPU非対応ブラウザ(古いSafari等)では表示されない。Chrome最新版を推奨

Step 2. 図面PDFの画像化と精読

AIはここを開いて読む: PDFの扱いと図面の読み取り手順

2-1. PDFの構成を把握する

まずPDFの各ページに何が描かれているかを一覧化します。

# 全ページのテキストから図面種別を抽出
for i in $(seq 1 $(pdfinfo ~/Desktop/図面.pdf | grep Pages | awk '{print $2}')); do
  echo "=== Page $i ==="
  pdftotext -f $i -l $i ~/Desktop/図面.pdf - 2>/dev/null | grep -E "平面図|立面図|電気|矩計|配置図|仕上表" | head -3
done

一条工務店の図面PDFの典型的な構成:

ページ内容3D化での用途
平面図間取り・寸法・グリッド番号最重要。壁・部屋・建具の座標源
立面図(4面)東西南北の外観・屋根形状・軒の出重要。屋根と高さの決定
電気図面コンセント・スイッチ・照明の位置と高さ設備配置(発展)
カラー立面図外壁・屋根の実際の色マテリアル設定
矩計図天井高・階高の断面高さの検証
仕上表内外装の材料一覧マテリアル設定

2-2. 精読可能な解像度で画像化

重要: デフォルトの低解像度PNGでは寸法線や記号が読み取れません。必ず200dpiで書き出してください。

cd ~/Documents/floorplan-3d
# 平面図(ページ番号は2-1で特定したもの)
pdftoppm -f 3 -l 3 -r 200 -png ~/Desktop/図面.pdf plan
# 立面図
pdftoppm -f 4 -l 4 -r 150 -png ~/Desktop/図面.pdf elev
# 電気図面
pdftoppm -f 2 -l 2 -r 200 -png ~/Desktop/図面.pdf elec

2-3. 4分割クロップして読む

200dpiの全体画像(3300×2300px程度)をそのまま読むと、AIの画像認識では細部が潰れます。必ず4分割して2倍に拡大してから読んでください。

from PIL import Image
im = Image.open('plan-03.png')
# 図面本体の領域を推定クロップ(余白・図枠を除く)
body = im.crop((350, 100, 2150, 2150))
bw, bh = body.size
quadrants = {
 'nw': (0, 0, bw//2+100, bh//2+100),
 'ne': (bw//2-100, 0, bw, bh//2+100),
 'sw': (0, bh//2-100, bw//2+100, bh),
 'se': (bw//2-100, bh//2-100, bw, bh),
}
for k, box in quadrants.items():
    c = body.crop(box)
    c.resize((c.width*2, c.height*2), Image.LANCZOS).save(f'plan-{k}.png')

各象限を Read ツールで画像として読み込み、記号・寸法・室名を読み取ります。

Step 3. 図面の読み解き方(日本の住宅図面の癖)

AIはここを開いて読む: 910mmグリッドと図面記号の読み方

3-1. 910mmモジュール(尺モジュール)が最重要

日本の在来工法・一条工務店の図面は、910mm(3尺)のグリッドに完全に乗っています。図面の外周に X0 X1 X2 ... Y0 Y1 Y2 ... という通り芯番号が振られており、これが910mmピッチです。

つまり、寸法を測る必要はありません。グリッドを数えるだけです。

図面上の値意味
1グリッド910mm(3尺)
0.5グリッド455mm(1.5尺)。トイレ・廊下幅などで頻出
0.25グリッド227.5mm。壁のずれ・ニッチで登場
1帖0.5グリッド × 1グリッド(910×1820mm)

座標変換は単純です。

M = 0.91  # 1グリッド = 910mm = 0.91m
def p(mx, my):
    return [mx * M, -my * M]   # 北をマイナスZにする(pascal-editorの座標系)

3-2. 検算式(転記ミスの早期発見)

読み取ったグリッド数が正しいか、図面に書かれた面積表と突き合わせます。

  • 建物寸法の検算: 10,010mm = 11グリッド × 9108,190mm = 9グリッド × 910
  • 床面積の検算: グリッドマス数 × 0.8281㎡(0.91² = 0.8281)
  • 帖数の検算: グリッドマス数 ÷ 2(例: 9マス = 4.5帖)

図面の「延床面積 69.66㎡ / 21.07坪」のような記載と一致すれば転記成功です。

3-3. 一条工務店の図面記号の読み方

建具記号(窓・ドア)

一条の窓記号は J JK JF VS などの記号 + 4桁数字で構成されます。数字は 幅×高さを尺貫法または実寸で表現 しています。

記号例読み方
J8371大開口スライディング。幅約2,515mm × 高さ約2,151mm
JF5915 +1677横すべり出し窓。幅約1,790 × 高さ455、+1677 は床からの取付高さ
JK2430N × 2たてすべり出し窓を2連。+1238 が付けば取付高さ1,238mm
VS1030 (B)縦すべり出し窓。(B) は網戸・仕様の区別
E-31ER玄関ドア(電子錠付きの型番)
SG311-1 SG300 SG33B室内引戸・開き戸。数字が違えば別サイズ
SGC-30B SGC-45E SGC-60Eクローゼット。数字が幅(30=900mm、45=1,350mm、60=1,800mm 目安)

重要: 数字から寸法を推定する際、確信が持てないものは図面の建具表(別ページにあることが多い)で確認してください。推定値を使う場合は、その旨をユーザーに報告します。

設備記号

記号例意味
KG19-27WDRキッチン(グレイスキッチン系)。27 = 幅2,700mm
CS19-B180Dカップボード。180 = 幅1,800mm
GM243R / GM2430グレイスドレッサー(洗面台)。24 = 幅1,200mm前後
1.25坪 1616浴室サイズ。1.25坪 = 1坪半サイズ
TD-12玄関ドア・土間まわりの記号
AC①(セ) AC②(ス)エアコン設置位置と種類
SA1 RA1 VA1換気の給気口(SA)・還気口(RA)・排気(VA)
床暖房1-A床暖房のゾーン区分
CH=2200その部屋の天井高(標準は2,400mm)
天井下地(G)天井への下地補強(照明・物干し設置用)
壁下地 H=0〜1820壁への下地補強と範囲(TV壁掛け等)

図面の線種

  • 太い実線: 壁(外壁は特に太い)
  • 細い一点鎖線: 通り芯(グリッド線)
  • 破線: 上部にあるもの(吊戸棚・下がり天井・小屋裏)
  • ハッチング(斜線): 土間・タイル・デッキなどの床仕上げ違い

3-4. 電気図面の読み方(コンセント・スイッチ・照明)

電気図面は平面図に赤字で設備が重ねて描かれています。位置と高さの両方が読み取れます。

記号意味標準取付高さ
⊐ または二重丸コンセント(アース無は3口が標準)床から250mm(記載なき場合)
H=900その設備の取付高さ指定図に明記された値を優先
H=1300キッチン腰上コンセント等1,300mm
● / ○ダウンライト・シーリングライト天井
WTC57583W 等の型番パナソニック製スイッチ・リモコン図のH=指定に従う
とったらリモコン着脱式リモコン(床暖房・給湯)H=1300前後
E付アース付きコンセント(洗濯機・冷蔵庫・エアコン)設備に応じる
200V AEYH用エコキュート等の200V専用回路H=1FL+40
専用E付電子レンジ・食洗機等の専用回路H=900〜1,300
情報ボックス PC用ルーター弱電盤・LAN機器H=2100等
分電盤用分電盤H=1800前後
火災警報器煙感知器(壁/天井)天井または壁上部

電気設備を3Dに反映する方法

pascal-editorでは、コンセント・スイッチは 壁に取り付くitem として配置できます。

# 壁付けアイテムの配置例
# wallId で壁を指定し、wallT (0〜1) で壁上の位置、position[1] で高さを指定
{
  "type": "item",
  "parentId": "<wall_id>",
  "wallId": "<wall_id>",
  "wallT": 0.35,                     # 壁の始点から35%の位置
  "position": [0.35 * wall_length, 0.25, 0],   # [壁沿い距離, 高さ, 壁からのオフセット]
  "asset": {
    "id": "power-outlet",
    "src": "/items/power-outlet/model.glb",
    "thumbnail": "/items/power-outlet/thumbnail.webp",
    "dimensions": [0.12, 0.12, 0.03],
    "attachTo": "wall",
    ...
  }
}

利用可能なGLBアセットは ~/Documents/pascal-editor/apps/editor/public/items/ls して確認してください。照明系は ceiling-light ceiling-lamp circular-ceiling-light floor-lamp などがあります。

注意: コンセントは1軒で50〜80箇所あるため、全部配置すると視認性が落ちます。ユーザーに「全部配置するか、主要なものだけにするか」を確認してください。

3-5. 図面読み取りの落とし穴(実際にハマったもの)

落とし穴1: 窓がない壁に窓を付けてしまう

平面図の壁の切れ目や、設備の記号線を窓と誤認しやすいです。窓・ドアは必ず 立面図と照合 してください。立面図に描かれていない開口部は存在しません。逆に立面図にあって平面図で見落としているケースもあります。

落とし穴2: 設備の出っ張り形状を単純化しすぎる

洗面台やカウンターは、図面上では「壁から何mm出っ張っているか」が正確に描かれています。GLBアセットのデフォルトサイズをそのまま使うと形が合いません。scale で図面の寸法に合わせ、L字・段差がある場合は複数のアイテムやslabを組み合わせてください。

落とし穴3: 室名の隣が別室

「押入」の隣が「洗面台」など、狭い区画が連続する水回りは特に取り違えやすいです。室名テキストがどの区画に属しているかは、囲んでいる壁線をたどって確認してください。

落とし穴4: 通り芯と壁面を混同する

図面の寸法は原則「壁芯(かべしん)」基準です。壁の内法(部屋の実際の広さ)は壁厚の半分ずつ小さくなります。3Dの壁も壁芯をstart/endに指定すれば整合します。

落とし穴5: 「上部アケル」「フキアゲ」等の注記を見落とす

天井の抜け・吹き上げ・下がり天井は3D形状に影響します。CH=2200 上部アケル 天井下地 などの注記は必ず拾ってください。

Step 4. 座標テーブルへの転記とシーンJSON生成

AIはここを開いて読む: 生成スクリプトのテンプレートと書き方

4-1. pascal-editorのシーンJSON仕様

シーン全体は {"nodes": {id: node}, "rootNodeIds": [...]} という形式です。

座標系: メートル単位、Y-up(Yが高さ)、右手系。2D座標は [x, z] で、北が −Z 方向。

ノード階層: site → building → level → 壁・床・部屋・屋根・家具

ID規則(重要): IDは型プレフィックス必須です。間違えるとインポートが拒否されます。

ノード種別IDプレフィックス
wall_
window_
ドアdoor_
床スラブslab_
部屋(ゾーン)zone_
屋根グループroof_
屋根セグメントrseg_
家具item_
level_
建物building_
敷地site_

4-2. 生成スクリプトのテンプレート

~/Documents/floorplan-3d/generate_scene.py として作成します。以下は実際に動作した完全なテンプレートです。座標テーブル部分(壁・窓・部屋の定義)だけをユーザーの図面に合わせて書き換えてください。

#!/usr/bin/env python3
"""間取り図 → pascal-editor シーンJSON 生成

座標系: メートル, Y-up。x = 東(+), z = 南(+)(北 = -z)
モジュール座標 (mx, my): グリッド番号。my は北向きに増加
変換: x = mx * M, z = -my * M
"""
import json

M = 0.91       # 1モジュール = 910mm(メーターモジュールなら 1.0)
EXT_T = 0.16   # 外壁厚
INT_T = 0.12   # 間仕切壁厚
WALL_H = 2.40  # 天井高(一条標準 2400)

nodes = {}

def p(mx, my):
    return [round(mx * M, 4), round(-my * M, 4)]

def add(node):
    nodes[node["id"]] = node
    return node["id"]

def base(id_, type_, name, parent, **extra):
    n = {"object": "node", "id": id_, "type": type_, "name": name,
         "parentId": parent, "visible": True, "metadata": {}}
    n.update(extra)
    return n

LEVEL = "level_1f"

# ============ 壁 ============
# 【向きの規約・重要】進行方向の左手が屋外になる順序で描く
# (back面 = 左手側 = exterior 扱いのため。逆だと外装が室内側に付く)
walls = []
def wall(id_, s, e, t, name):
    walls.append((id_, s, e, t, name))

# 外周壁(グリッド座標で指定。ここをユーザーの図面に合わせて書き換える)
wall("wall_ext_s",  (11, 1), (0, 1),  EXT_T, "外壁 南")
wall("wall_ext_e",  (11, 8), (11, 1), EXT_T, "外壁 東")
wall("wall_ext_n",  (0, 8),  (11, 8), EXT_T, "外壁 北")
wall("wall_ext_w",  (0, 1),  (0, 8),  EXT_T, "外壁 西")
# 間仕切壁
wall("wall_p1", (0, 5.5), (2, 5.5), INT_T, "浴室 南")

wall_children = {w[0]: [] for w in walls}

# ============ 開口部(窓・ドア)============
# dist = 壁の start からの中心距離[m]
def window(id_, wall_id, dist_m, width, height, center_y, wtype="sliding", name=""):
    add(base(id_, "window", name or id_, wall_id,
             position=[round(dist_m, 4), round(center_y, 4), 0],
             rotation=[0, 0, 0], wallId=wall_id,
             width=width, height=height,
             windowType=wtype, openingKind="window"))
    wall_children[wall_id].append(id_)

def door(id_, wall_id, dist_m, width, height, dtype="hinged", name=""):
    add(base(id_, "door", name or id_, wall_id,
             position=[round(dist_m, 4), round(height / 2, 4), 0],
             rotation=[0, 0, 0], wallId=wall_id,
             width=width, height=height, doorType=dtype))
    wall_children[wall_id].append(id_)

# 例: 南面の大開口(start が X11 なので dist は X11 からの距離)
window("window_main", "wall_ext_s", (11 - 5.65) * M, 2.51, 2.15, 0.05 + 2.15/2,
       "sliding", "大開口スライディング")
door("door_entrance", "wall_ext_n", 1.5 * M, 0.98, 2.30, "hinged", "玄関ドア")

# ============ 壁ノードの登録 ============
EXT_TILE = {"properties": {"color": "#3d4045", "roughness": 0.65, "metalness": 0.05}}
for wid, s, e, t, name in walls:
    extra, front, back = {}, "unknown", "unknown"
    if wid.startswith("wall_ext_"):
        extra["exteriorMaterial"] = EXT_TILE
        front, back = "interior", "exterior"
    add(base(wid, "wall", name, LEVEL,
             start=p(*s), end=p(*e), thickness=t, height=WALL_H,
             children=wall_children[wid],
             frontSide=front, backSide=back, **extra))

# ============ 床スラブ ============
outline = [(0, 1), (11, 1), (11, 8), (0, 8)]
add(base("slab_floor", "slab", "1階床", LEVEL,
         polygon=[p(*pt) for pt in outline], holes=[], holeMetadata=[],
         elevation=0.02, thickness=0.2, autoFromWalls=False))

# ============ ゾーン(部屋)============
zone_defs = [
    ("zone_ldk", "LDK (22.42帖)", [(0,1),(8,1),(8,8),(0,8)], "#f59e0b"),
]
for zid, name, poly, color in zone_defs:
    add(base(zid, "zone", name, LEVEL,
             polygon=[p(*pt) for pt in poly],
             autoFromWalls=False, boundaryWallIds=[],
             spaceRole="room", roomNumber="", enclosureStatus="auto",
             floorFinish="", wallFinish="", ceilingFinish="",
             ceilingHeight=WALL_H, occupancy="",
             clearDimensionPolicy="none", color=color))

# ============ 屋根 ============
# 【重要】roof-segment は必ず roof ノードの子にする
PITCH = 19.29   # 3.5寸勾配 = atan(3.5/10)。4寸なら21.8、5寸なら26.57
PI = 3.14159265
SOLAR_TOP = {"properties": {"color": "#1f2630", "roughness": 0.3, "metalness": 0.25}}
ROOF_EDGE = {"properties": {"color": "#2a2d31", "roughness": 0.5, "metalness": 0.1}}
DARK_TILE = {"properties": {"color": "#3d4045", "roughness": 0.65, "metalness": 0.05}}

def rseg(id_, name, mx0, mx1, my0, my1, rot, pos_y, wall_h, **extra):
    cx, cz = (mx0 + mx1) / 2 * M, -(my0 + my1) / 2 * M
    return add(base(id_, "roof-segment", name, "roof_1",
                    position=[round(cx, 3), pos_y, round(cz, 3)], rotation=rot,
                    width=round((mx1 - mx0) * M, 3), depth=round((my1 - my0) * M, 3),
                    roofType="shed", pitch=PITCH, wallHeight=wall_h, overhang=0.25,
                    wallThickness=0.1, deckThickness=0.1, shingleThickness=0.05,
                    children=[], **extra))

# shed(片流れ)は local -Z 側が高い。rotation=PI で南向きに反転
rseg("rseg_main", "大屋根", 0, 11, 0.5, 5.75, 0.0, 2.40, 0.10)
rseg("rseg_north", "北下屋", 0, 11, 5.75, 8.5, PI, 2.40, 0.62)

add(base("roof_1", "roof", "屋根", LEVEL, position=[0,0,0], rotation=0,
         topMaterial=SOLAR_TOP, edgeMaterial=ROOF_EDGE, wallMaterial=DARK_TILE,
         children=["rseg_main", "rseg_north"]))

# ============ 家具・設備 ============
# 【重要】asset.thumbnail が必須。無いとインポート拒否される
ITEM_IDS = []
def item(id_, asset_id, dims, offset, mx, my, ry=0.0, scale=(1,1,1), name=""):
    ITEM_IDS.append(id_)
    add(base(id_, "item", name or asset_id, LEVEL,
             position=[round(mx*M, 3), 0, round(-my*M, 3)],
             rotation=[0, ry, 0], scale=list(scale), children=[],
             asset={"id": asset_id, "name": name or asset_id, "category": "furniture",
                    "thumbnail": f"/items/{asset_id}/thumbnail.webp",
                    "src": f"/items/{asset_id}/model.glb",
                    "dimensions": dims, "offset": offset,
                    "rotation": [0,0,0], "scale": [1,1,1]}))

HPI = 1.5708  # 90度
item("item_kitchen", "kitchen", [2.5,1.1,1], [0,0,0], 5.5, 5.85, 0, (1.08,1,0.75), "キッチン")

# ============ 階層 ============
add(base(LEVEL, "level", "1階", "building_1", level=0, height=3.0,
         children=[w[0] for w in walls] + ["slab_floor"]
                  + [z[0] for z in zone_defs] + ["roof_1"] + ITEM_IDS))
add(base("building_1", "building", "自邸", "site_1",
         position=[0,0,0], rotation=[0,0,0], children=[LEVEL]))
add(base("site_1", "site", "敷地", None,
         polygon={"type": "polygon",
                  "points": [p(-3,-3), p(14,-3), p(14,14), p(-3,14)]},
         children=["building_1"]))

graph = {"nodes": nodes, "rootNodeIds": ["site_1"]}
import os
out = os.path.expanduser("~/Documents/floorplan-3d/my-house.json")
with open(out, "w", encoding="utf-8") as f:
    json.dump(graph, f, ensure_ascii=False, indent=1)
print(f"nodes: {len(nodes)} -> {out}")

4-3. 家具アセットの一覧を確認する

ls ~/Documents/pascal-editor/apps/editor/public/items/

主要なアセットと標準寸法 [幅, 高さ, 奥行]:

asset_iddimensions用途
kitchen[2.5, 1.1, 1]システムキッチン
kitchen-counter[2, 0.8, 1]カップボード
fridge[1, 2, 1]冷蔵庫
dining-table[2.5, 0.8, 1]ダイニングテーブル
dining-chair[0.5, 1, 0.5]椅子
sofa[2.5, 0.8, 1.5]ソファ
coffee-table[2, 0.4, 1.5]ローテーブル
tv-stand[2, 0.4, 0.5]TVボード
double-bed[2, 0.8, 2.5]ダブルベッド
closet[2, 2.5, 1]クローゼット
toilet[1, 0.9, 1]トイレ
bathroom-sink[2, 1, 1.5]洗面台
bathtub[2.5, 0.8, 1.5]浴槽
washing-machine[1, 1, 1]洗濯機
drying-rack[2, 1.1, 1]物干し
piano-ピアノ
indoor-plant-観葉植物

dimensions はアセット固有の値なので上表のとおりに指定し、実際のサイズ調整は scale で行います(例: 幅1,800mmのカップボードなら scale=(0.9, 1, 0.5))。

Step 5. インポートと検証ループ

AIはここを開いて読む: ブラウザでの読み込みと図面との突き合わせ

5-1. シーンの生成とインポート

cd ~/Documents/floorplan-3d && python3 generate_scene.py

ブラウザで http://localhost:3002 を開き、次の手順でインポートします。

  1. 左サイドバーの 歯車アイコン(設定)をクリック
  2. SAVE & LOAD セクションの Load Build をクリック
  3. 生成した my-house.json を選択
  4. スキーマ検証ダイアログが出る → エラーがなければ Replace current scene

AIが自動でこれを行う場合: chrome-devtools MCPが使える環境なら、Load Build ボタンのuidに対して upload_file を実行することでファイル選択ダイアログを経由せず直接インポートできます。ブラウザ操作MCPがない場合は、ユーザーに手動操作を依頼してください。

5-2. 検証の2軸

検証軸操作照合先
平面の正確さ上部の 2D ボタン平面図
立体の正確さ3D + 画面下の Orbit Left/Right(45°刻み)立面図4面
内観Preview ボタン → ウォークスルー完成イメージ
屋根内部Full height トグルで屋根を透過平面図

5-3. 修正ループ

差分を見つけたら generate_scene.py の座標テーブルを修正 → 再生成 → 再インポート、を繰り返します。2〜3周は必ず必要です。

チェックリスト:

  • 全部屋の位置・広さが平面図と一致しているか
  • 帖数の検算が合っているか
  • 窓・ドアの位置とサイズが図面どおりか
  • 立面図に描かれていない窓を付けていないか(頻出ミス)
  • 屋根の勾配・段差・軒の出が立面図4面と一致しているか
  • 外壁・屋根の色がカラー立面図と一致しているか
  • 設備(キッチン・浴槽・トイレ・洗面台)が図面の位置にあるか
  • 設備の出っ張り・向きが図面どおりか

Step 6. よくある失敗と対処

AIはここを開いて読む: エラー別トラブルシューティング
症状原因対処
インポートで Invalid input エラー(roof-segment)IDプレフィックスが roofseg_ になっているrseg_ に修正
インポートで asset.thumbnail エラーitemノードにthumbnailがないasset.thumbnail を追加(/items/<id>/thumbnail.webp
屋根が全く表示されないroof-segmentをlevel直下に置いている必ず roof ノードを作りその子にする。levelのchildrenにはroofのIDだけ入れる
外壁の色が室内側に付く壁の描画方向が逆壁のstart/endを入れ替える(進行方向の左手が屋外)
窓・ドアが表示されない壁のchildrenに登録していないparentId設定に加え、親壁のchildren配列にもIDを追加
建物が真っ黒で何も見えないカメラが屋根の中に入っているホイールでズームアウト、またはTop Viewボタン
家具が床にめり込む/浮くscaleのY値が不適切Y方向のscaleは1.0を基本にし、幅・奥行だけ調整
bun run devが起動しないポート3002が使用中lsof -ti:3002 | xargs kill -9
3D画面が真っ白WebGPU非対応Chrome最新版を使う
ブラウザ操作で要素が見つからないページ再描画でuidが変わったsnapshotを取り直してから操作

カメラ操作(AIがスクリプトで操作する場合)

// ズーム
const canvas = document.querySelector('canvas');
const r = canvas.getBoundingClientRect();
canvas.dispatchEvent(new WheelEvent('wheel', {
  clientX: r.left + r.width/2, clientY: r.top + r.height/2,
  deltaY: 120, bubbles: true, cancelable: true   // 正=ズームアウト
}));

回転は画面下部の Orbit Left / Orbit Right ボタン(45°刻み)を使うのが確実です。ポインタイベントでのドラッグ回転は座標計算が煩雑になります。

Step 7. 完成データの活用

AIはここを開いて読む: エクスポートと共有

すべてのエクスポートは 設定(歯車)→ EXPORT セクションから行えます。

形式用途
Save Build(JSON)編集後のシーンを保存。このファイルを渡せば誰でも同じ3Dを再現できる
Export GLB3Dモデル標準形式。Blender・Three.js・動画制作(Remotion等)に持ち込める
Export STL3Dプリント用
Export OBJ汎用3D形式
Full floor plan平面図として書き出し

発展: さらに精度を上げるには

  1. 電気設備の配置 — Step 3-4の電気図面の読み方に従い、コンセント・スイッチ・照明を壁付けitemとして配置
  2. 下がり天井の再現CH=2200 などの記載がある部屋は ceiling ノードで個別に天井を作る
  3. 敷地・外構 — 配置図から敷地形状・駐車場・アプローチをslabfenceで追加
  4. 太陽光パネルの分割表現solar-panel ノードで実際の枚数・配列を再現
  5. 家具の実物寸法化 — 実際に購入する家具のサイズでscaleを調整すれば、家具配置シミュレーションになる

実際に作ってみた結果

私の家(一条工務店 GRAND SMART 平屋・埼玉県狭山市)で実際にやってみた結果です。

3Dモデルの北側外観。玄関ドア、トイレの小窓、防音室の窓、玄関ポーチの下屋、招き屋根の段差

北面(玄関側)。玄関ポーチの下屋、招き屋根の段差、窓の位置と大きさも図面どおりです

生成した3Dモデルの2D平面表示。LDK22.42帖、洋室2、防音室、脱衣室、浴室、押入B、トイレ、玄関ホール、収納の各室名と家具の配置

2D表示に切り替えると平面図として確認できます。部屋名・帖数・天井高・家具・建具まで入っています

壁を低くして室内を見せた3Dモデル。フローリング、ダイニングテーブル、観葉植物、ベッドなどの家具が配置されている

壁を下げる表示にすると内部が見えます。図面の設備記号に対応する家具を配置しています

再現できたもの

  • 全部屋の位置と広さ(LDK 22.42帖、防音室・洋室 各4.5帖、1.25坪バス、脱衣室、玄関ホール、トイレ、押入、収納)
  • 全開口部(大開口スライディング、高窓、たてすべり出し窓×4、玄関ドア、室内建具6箇所)
  • 3.5寸勾配の招き屋根(段違い片流れ)、軒の出、妻壁
  • ハイドロテクトタイル・ブラックの外壁、太陽光一体屋根
  • ウッドデッキ、玄関ポーチ
  • 家具・設備21点(キッチン、カップボード、冷蔵庫、浴槽、洗面台、トイレ、洗濯機、ピアノ、ベッド、ソファ等)

ノード数: 78(壁21・ドア7・窓10・部屋9・屋根3・家具21ほか) 所要時間: 環境構築込みで約2時間

まだできていないこと

  • 電気設備(コンセント・スイッチ・照明)の配置
  • 下がり天井(CH=2200等)・垂れ壁
  • 太陽光パネルの枚数分割表現

なぜこの方法がいいのか

「間取り図 → 3D」はAIで自動変換するツールもありますが(FloorplanToBlender3d、CubiCasa5Kなど)、いずれも欧米の間取りで学習されており、日本の尺モジュール・一条の図面記号では精度が出ません。

一方この方法は、910mmグリッドという日本の住宅図面の性質を利用して、寸法推定を一切せずに座標を確定させるアプローチです。グリッドを数えるだけなので、AIが図面を読み間違えるリスクが大幅に下がります。

商用ツールではFloorplanner(FML形式のAPI公開)が唯一の対抗馬ですが、無料枠は透かし付き・低解像度で、本格利用は有料前提です。今回使ったpascalorg/editorはMITライセンスの完全無料OSSで、すべてローカルで完結します。


おわりに

家づくり中の方にとって、間取り図って何度も見返すものだと思います。でも2次元の図面だけだと、実際の空間の広がりや、窓から見える景色、家具を置いたときの余白って、なかなかイメージしきれないんですよね。

3Dにしてぐるぐる回してみると、「ここの動線ちょっと狭いかも」「この窓の位置だと隣家と目線が合うな」みたいな気づきが出てきます。打ち合わせ前にやっておくと、質問の質が変わってくるはずです。

この記事のURLをAIに渡すだけなので、よかったら試してみてください。

よくある質問

プログラミングの知識がなくても作れますか?
作れます。この記事はAIが読んで実行するための手順書なので、あなたがやるのは3つだけです。図面PDFを用意する、Claude CodeまたはCodexを起動する、「この記事のURLとPDFを読んで3D化して」と伝える。コードを書くのも環境構築もAIが全部やります。
費用はかかりますか?
3Dエディタ(pascalorg/editor)はMITライセンスの無料OSSで、すべてローカル環境で動くため利用料はかかりません。必要なのはClaude CodeまたはCodexの利用料だけです。図面データも契約者なら一条工務店のタブレットから無料で取得できます。
一条工務店以外の家でも作れますか?
作れます。ただしこの手順書は一条工務店の910mmモジュール(尺モジュール)を前提に最適化しているため、他社の図面ではグリッドの読み取り方が変わります。メーターモジュールの会社なら1000mm、ツーバイフォーなら図面の寸法線を直接読む方式にAIへ指示してください。
作った3Dモデルは他の人に共有できますか?
できます。完成データはJSONファイル1つにまとまっているので、そのファイルを渡せば相手も同じ3Dを再現できます。GLB形式で書き出せばBlenderや動画編集ソフト、Three.jsを使ったWebサイトにも持ち込めます。
図面PDFはどこから手に入りますか?
一条工務店の契約者なら、貸与されているタブレット(i-tablet)の図面閲覧アプリからPDFを書き出せます。打ち合わせ資料としてもらった紙図面しかない場合は、スマホのスキャンアプリでPDF化しても構いませんが、寸法線が読み取れる解像度が必要です。

ろれさん

ろれさん

一条工務店グランスマートで埼玉県に21坪の平屋を建てた施主。家づくりの経験をYouTube・ブログ・Webツールで発信中。

一条工務店の紹介をろれさんに依頼する 紹介実績10人突破・入力3分・契約の義務なし 最大35万円相当のオプションが無料 → 一条工務店の紹介制度を徹底解説 【2026年最新】一条工務店の紹介制度を徹底解説