
2026/07/02 10:00
ブラウザ上の LibreCAD
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
LibreCAD は、C++ および Qt を用いて構築された無料の GPL ライセンス付 2D CAD アプリケーションであり、現在は WebAssembly を通じて Web ブラウザのタブ内で完全に動作し、デスクトップへのインストールは不要です。この移植版では、Emscripten と Qt の WebAssembly プラットフォームサポートを利用して、同一の C++ ソースコードを WebAssembly にコンパイルしており、ロジックを書き換えることも、サーバーサイドレンダリングに依存することもしない最初の読み込みには約 18 MB(圧縮形式:Brotli)が必要です。現在、完全な互換性を確保するには、Google Chrome または Edge バージョン 137 以降のような Chromium ベースのブラウザが必要であり、Firefox および Safari は JSPI が不足しているためサポートされていません。技術的な迂回措置により、Qt の blocking
exec() 呼び出しによってブロックされていたネストしたモーダルダイアログといった複雑な問題に対処され、Asyncify およびネイティブ JSPI を用いて任意のネスタリングを実現しました。ビルドには Qt 6.9.3(wasm-port ブランチ)、Emscripten 4.0.7、C++17、Ubuntu 24.04 ベース環境が使用され、wasm32 メモリモデルは 4 GB で capped されています。WebAssembly の例外機能は有効化され、カスタムパッチにより DOM イベント/タイマーコールバックを「promise 化」しています。パフォーマンス向上のため、バックストアを RGBA8888 から premultiplied ARGB32 に変更し、SIMD パスを採用した結果、フレームレートを約 4–5 fps から約 15 fps に向上させ、約 3 倍の速度向上を実現しました。ファイル処理には JavaScript シムを使用しており、getOpenFileContent および saveFileContent は MEMFS と IndexedDB を経由します。CAD フォントおよびハッチパターンは 30 MB のデータパッケージとしてバンドルされています。エクスポート機能には QPdfWriter を用いた PDF エクスポート、ダウンロード可能な DXF ファイル、SVG サポートが含まれます。物理的な印刷には、生成された PDF をブラウザが印刷する必要があります。ソースコードは github.com/magik6k/LibreCAD-Web の wasm-port ブランチでホストされており、upstream へのガード付き変更は github.com/LibreCAD/LibreCAD にあり、条件 #if defined(Q_OS_WASM) で制御されています。本文
LibreCAD を WebAssembly (Wasm) へ移植:ブラウザだけで動く本物の 2D CAD アプリ
はじめに:なぜこのプロジェクトが必要か
- 簡易的な 2D 図面の描画ニーズ:床間取り图等を描きたい場合、CAD ユーザーではないため専用のソフトウェアをインストールしたくありませんでした。
- 現在の Web 環境への適応:2026 年現在、ログインなしでタブを開いてすぐ使えるべきものなのに、ローカルアプリ(ダウンロード・インストール・起動)の必要があることに違和感を感じていました。
- アプローチの転換:既知の無料デスクトップアプリを使わず、「オープンソースで既存の成熟したツール」を見つけ、LLM に WebAssembly (Wasm) への移植を指示することを決定しました。
- Qt チームによる WebAssembly 支援と、成熟した Wasm エコシステムのお陰で、プロセスは驚くほど簡単かつ成功裏に進みました。
プロジェクト概要:何を実装したか?
- 成果物:LibreCAD という無料の GPL ライセンス 2D CAD アプリを、JavaScript の再実装やサーバーサイドレンダリングではなく、正確に同じ C++ ソースコードを用いて WebAssembly にコンパイルしました。
- プラットフォーム:Emscripten および Qt の公式 WebAssembly プラットフォーム支援機能を利用しています。
- 動作環境:本物のデスクトップアプリケーションがブラウザのタブ内で動作します。
注記:以下のコンテンツは LLM によって作成されましたが、技術的な内容は概ね正確です。類似プロジェクトにありがちな「FAFO(愚かしく失敗するスタイル)」ではなく、実用的な成果を上げた試みですが、詳細な検査ではバグが含まれる可能性があります。
動作方法と要件
- 起動手順:以下のリンクからソースコードを読み込みます。
- github.com/magik6k/LibreCAD-Web(※本文の「このサイトで」という表現は、GitHub リポジトリのデモページや Wasm ファイルをブラウザで実行することを指します)
- 初期読み込み量:初回起動時に約 18 MB(Brotli 圧縮済み)をダウンロードします。
- その後はブラウザがキャッシュするため、次回以降は速くなります。
- 必須ブラウザ:**Chromium ベースのブラウザ(Chrome または Edge 137 以降)**が必要です。
- Firefox や Safari はまだ動作しません(後述する技術的理由による)。
実装の詳細:難所と解決策
1. ツールチェーンとコンパイル戦略
- 環境:Ubuntu 24.04、Emscripten、Qt を含む Docker イメージを使用。
- ビルド方法:
- Qt の独自ツールチェーン (
) を使用し、qt.toolchain.cmake
を正常動作させるよう調整しました。find_package(Qt6) - デスクトップ版の起動パス(CLI 引数解析、スプラッシュ画面等)は
でガードされており、Wasm ビルドには影響ありません。#ifndef Q_OS_WASM
- Qt の独自ツールチェーン (
2. GUI の描画とイベント処理
- 基本動作:Qt for WebAssembly は WebGL を介して描画し、プラットフォームプラグインでブラウザイベントを処理します。メインウィンドウやツールバーの表示に問題はなく問題です。
- ネストされたダイアログの問題(難所):
- デスクトップアプリ特有の
はブロック呼び出しですが、Web 上ではメインスレッドをブロックできません。QDialog::exec() - Asyncify(従来の解決策)の限界:Qt の公式 Asyncify サポートはネスト深度が 1 レベルのみ対応するため、設定ダイアログ内からカラーピッカーを開くと 2 回目のサスペンド先がなく、アプリ全体がフリーズ(Wedging)しました。
- JSPI(解決策):WebAssembly JavaScript Promise Integration (JSPI) を採用し、無制限にネストできるネイティブブラウザサスペンドメカニズムを実現しました。
- Qt 6.9 で
を使用し、Wasm 例外 (-device-option QT_EMSCRIPTEN_ASYNCIFY=2
) を有効化。-fwasm-exceptions - JSPI と Wasm 例外を組み合わせることで、モダルダイアログ、ドロップダウン、ネストされたカラーピッカーが任意の深度で動作します。
- Qt 6.9 で
- デスクトップアプリ特有の
3. キャンバスの高速化
- 課題:初期ビルドではフレームレートが 4〜5 フープ(画像/秒)と非常に遅くでした。
- 原因:Qt の Wasm バッキングストアが HTML キャンバスで想定される「ストレートアルファの RGBA8888」ではなく、非最適化形式だったため、転送時に重複した変換処理が発生していました。
- 解決策:バッキングストアを事前乗算済みの ARGB32(Qt の最適化形式) に変更。
- これにより合成処理を SIMD パスに送り込み、1 つの変換で RGBA バイトを生成可能になりました。
- 結果としてフレームレートは約 3 倍向上し、エンジン全体の性能改善となりキャンバスのハックでは済ませられませんでした。
4. ファイルシステムのない環境でのデータ管理
- 制限:ブラウザには真のファイルシステムがないため、Qt の標準ヘルパー API は直接機能しません。
- 実装したシム層:
- Open(読み込み):ファイル選択後、JS で読み取り、Emscripten のメモリ内ファイルシステム (MEMFS) に直接書き込みます。
- Save(保存):MEMFS にシリアライズし、Blob に渡し、ブラウザのダウンロードリンクを生成します。
- リソースバンドル:CAD フォント (47 ファイル) やハッチパターン (30 MB) は MEMFS にプリロードされ、設定は IndexedDB で永続化しています。
5. ビルドと実行環境の仕様
- Qt バージョン:6.9.3(ソースから Wasm 用へ構築)。
- 依存ライブラリ:Emscripten 4.0.7、ベースイメージ Ubuntu 24.04 (Docker)。
- スレッドモデル:シングルスレッド、メモリモデルは wasm32 (4 GB ティンバー)。
実機確認レポート:テスト項目と結果
✅ 動作する機能
以下のすべての機能がブラウザ内で正常に動作しています。
- ファイル操作:DXF の読み込み・編集・保存(ダウンロード)、DWG の読み取り。
- 描画ツール:ライン、円弧、円、ポリライン、スプライン、ハッチ、寸法、テキストの作成。
- 編集ツール:移動、回転、スケール、鏡像、トリム、ベベル、オフセット、破砕など全ツール。
- プロジェクト管理:レイヤー操作、ブロック定義・挿入、ライブラリから図面の読み込み。
- 表示機能:パン(ドラッグ)、ズーム(ホイール)、モーダルダイアログ・ドロップダウンのネスト動作。
- 出力形式:SVG エクスポート、PDF エクスポート(QPdfWriter 経由でのダウンロード)。
- 設定・ローカライズ:IndexedDB を利用した設定持続性、30 言語以上の翻訳対応 (.qm ファイル)。
⚠️ 動作しない機能や制限事項
以下の項目は Web プラットフォームの制約によりサポートされていません。
- 物理プリンターへの直接印刷:対応なし(PDF をダウンロードして印刷してください)。
- マルチウィンドウ (MDI):OS レベルの複数ウィンドウ化は不可、タブ内で 1 つの実行環境です。
- ファイルシステムへの保存:ブラウザは「開いたファイル」に書き戻せないため、「保存」は常に**ダウンロードされたコピー(別ファイル)**になります。ディスク上での上書き編集は手動で行う必要があります。
- 最近使用履歴 (MRU):リロードすると消えます(メモリアンダー上の永続ハンドルがリセットされるため)。
- ブラウザサポート:Chromium ベースのみ(Chrome/Edge 137+)。Firefox/Safari は JSPI 依存のため未対応です。
テスト手順(お試しください)
以下のステップで簡易的な 2D スケッチや図面を確認できます。
- アプリ起動:リンクから読み込み待ち(初回は数秒〜数十秒かかります)。
- DXF の開く:
からコンピュータ上の DXF ファイルを選択します。(サンプルがない場合はリポジトリ内を探してください)File → Open - 線の描画:ラインツールを選択し、キャンバス上で 2 カ所をクリックして図形を作成します。
- パン/ズーム:マウスホイールで拡大縮小、中指ドラッグ(またはクリック&ドラッグ)で移動させます。
- 保存:
から DXF ファイルをダウンロードします。File → Save As - PDF エクスポート:
で PDF を生成し、ダウンロードします。File → Print
技術仕様とライセンス情報
ビルド環境
- C++ スタンダード:C++17
- ビルド方法:ソースコードからの純粋な WebAssembly コンパイル(再実装なし)。
- 依存関係:
(DWG 読み込み用) はバンドル済み。libdxfrw
バイナリサイズ(Brotli 圧縮後)
- メインバイナリ (Wasm): ~18 MB (未圧縮 39 MB)
- データファイル(フォント+パターン): ~2.2 MB (未圧縮 30 MB)
- ランタイムグルー (JS): ~52 KB (未圧縮 264 KB)
- 合計転送量: 約 18 MB
ソースコードとライセンス
- フォーク先:github.com/magik6k/LibreCAD-Web (wasm-port ブランチ)。
- アップストリーム:github.com/LibreCAD/LibreCAD。
- 変更内容の隔離:すべての Wasm 特化変更は
や#if defined(Q_OS_WASM)
などのガードで囲まれており、デスクトップ版への影響を完全に排除しています。#ifndef LC_NO_PRINT - ライセンス:GPL-2.0。Wasm バイナリも同じライセンス下にあります。
まとめ
このプロジェクトでは、LLM の指示に従いながら、LibreCAD という成熟したオープンソースアプリの本物ごとを WebAssembly に移植することに成功しました。 難しかったネストされたダイアログ処理やキャンバス速度向上は、JSPI や最適化バッキングストアの導入によって解決され、ブラウザ上で本格的な 2D CAD 作業が可能になっています。
今後の Firefox/Safari への JSPI サポートが広がることで、さらに多くのプラットフォームで利用可能になることを期待しています。