Simutrans向けの、ブラウザ内で動作する地形エディタです。本実装を進めており、画像の読込、3D地形と水面の表示、ドラッグによる造成、Undo/Redo、BMP・PNG書き出しに対応しています。
GitHub Pagesで開く。Chrome・Edge最新版に対応し、バックエンドは不要です。ファイルはブラウザ内で処理します。設定と一時履歴の保存先はオリジンごとに分かれるため、ローカル版の設定や履歴は公開版へ引き継がれません。
Node.js 22.18以降とnpmを用意して実行します。
npm ci
npm run dev表示されたローカルURLをChromeまたはEdgeの最新版で開きます。初回は128四方の平坦なマップで始まります。地図名・サイズ・未保存状態は画面上部に表示します。ブラシの種類・半径・強さと真上/斜めの視点はブラウザへ記憶します。グリッド表示のON/OFFも記憶します。マップや互換設定は記憶しません。幅・高さ(タイル数)を指定して平坦な地形を新規作成するか、マップ画像を読み込んで開始します。新規作成・画像読込では確認後に現在の地形とUndo履歴を置き換えます。左ドラッグで連続造成し、右ドラッグで回転、ホイールでズームします。盛土・掘削は開始点の高さ±強さ、平坦化は開始点の高さに固定します。静止して0.5秒長押しすると盛土・掘削を繰り返せます。通常のドラッグは高さを固定し、長押しも含め離すまでを1回のUndoで戻せます。「なだらかにする」は近傍平均へ近づける平滑化で、強さ1〜8は平均化の反復回数です。「傾斜をならす範囲」1〜16(既定4)を広げると、段差や山の肩を広い幅にならします。「凹凸をならす」は平均化、「傾斜を緩める」はブラシ中央を開始点の高さに近づけて勾配を下げ、外周へ滑らかにつなぐ方式です。斜面条件を保つ補正はブラシ外へ波及する場合があります。Escapeで途中のドラッグを取り消します。海面表示は近似で、ゲームの湖・河川・砂浜生成は再現していません。画像から復元できない互換設定は、ゲーム側と合わせて指定してください。
キーボード操作は、1〜4 で造成ツール、[ / ] でブラシ半径、- / + で強さ、G でグリッド、V で真上/斜めを切り替えます。矢印キーは長押しで画面方向へカメラを平行移動します。Ctrl+Z でUndo、Ctrl+Shift+Z / Ctrl+Y でRedo、Ctrl+O で画像を開き、Ctrl+S でPNGを書き出します。MacではCtrlの代わりにCommandを使えます。入力中・IME変換中・造成中はショートカットを抑止し、Escape は造成を取り消します。
履歴は画素差分をWorkerからIndexedDBへ非同期保存します。初期予算は未保存キュー64 MiB、保存済み512 MiB、最大1000操作で、予算設定はlocalStorageに保持します。Undo/Redoの読込中は編集を待機します。容量超過や保存失敗では造成を停止し、現在の地形と未保存履歴を保持します。画像を書き出すか、確認後に履歴を破棄して再開・RAM履歴へ切り替えられます。履歴はブラウザタブごとの一時データで、編集再開用セーブではありません。
書き出しはBMPまたはPNGボタンで選べます。PNGは8bitグレースケールの可逆圧縮で、BMPと同じ標高サンプルを保存します。互換設定はどちらの画像にも含まれないため、ゲーム側と合わせてください。
互換設定には検証対象Standardのソース版、設定候補、標高上下限を表示します。対象ゲーム版の標高上限127に対し、エディタは内部補正の余裕を残して125までに制限しています。高さ変換・範囲・係数・斜面条件の変更は、必要な補正を確認し履歴を破棄します。海面だけの変更は確認ダイアログなしで適用し、履歴と画像の未保存状態を維持します。画像値の変換条件を変えた場合は再書き出しが必要です。
画像読込時に、選択した互換設定で書出可能な標高と自然地形の斜面条件へ補正します。置換確認に補正画素数を表示し、補正があれば未保存として扱います。取り消すと現在の地形と履歴を保持します。元画像の未補正標高を保持する機能はありません。
左パネルに造成と表示、右パネルにファイルと互換設定を配置しています。履歴容量・操作ガイド・マップ詳細は折り畳めます。カーソル位置は左上原点の格子X/Yと、地形の表示標高で示します。グリッドは地形と水面へ表示し、遠距離では線のちらつきを抑えるため薄くなります。
入力は非インターレース8bitの灰階/RGB/不透明RGBA PNG、8bit・24bit BMP、PPM P6(最大値255)に対応します。PNGパレット・16bit・半透明、BMP RLEのdelta命令などは明示的に拒否します。各辺の上限は32,766、エディタの既定上限は総画素数67,108,864・ファイル256 MiBです。「表示品質・上限設定」で総タイル数(16,384〜268,435,456)、ファイル容量(1〜1024 MiB)、ブラシ半径上限(1〜256)、水面予算(自動または16〜256 MiB)、表示セル予算(約100万〜1600万、既定約400万)を変更し、ブラウザへ記憶できます。4096四方を超える場合は概算メモリを警告します。描画は分割し、カメラに映る範囲とズーム率に応じて表示予算を配分します。カーソルから離れた画面内の地形も詳細化し、画面外は粗く表示します。編集と保存は全解像度を維持します。水面予算の自動設定はマップ面積に応じた16〜64 MiBです。予算を下回るまで画像を粗くする処理は行わず、超過した更新は拒否します。これは現在の処理制限で、あらゆる端末での快適な操作を保証する値ではありません。
npm run lint
npm test
npm run build通常のアプリ検証に外部Simutransソースやネイティブコンパイラは不要です。ブラウザテストは、Chrome・Edgeをインストールして npm run test:browser、または次のChromium構成で実行します。
npx playwright install chromium
npx playwright test --config playwright.ci.config.ts
npm run test:deploymenttest:deployment は直前にビルドした成果物をサブディレクトリで配信し、Worker・履歴・PNG往復を検証します。npm run validate:prototype は文書・単体・ビルド・Chrome/Edge検証をまとめて実行します。
実ゲーム互換のネイティブ検証は任意です。対象ソースは af90444e46dfd422bfdf80518aaa568659ec6b00 に固定し、ソース改変・実行ファイル・ハーネスのハッシュを検査します。PowerShellと、C++17・libpng・zlibを利用できるGCC系コンパイラが必要です。Windowsでの設定例:
$env:SIMUTRANS_SOURCE='任意の場所のSimutransソース'
$env:SIMUTRANS_COMPILER_BIN='任意の場所のコンパイラとDLLのディレクトリ'
npm run validate:heightmaps
$env:VALIDATE_NATIVE='1'
npm run test:browserコンパイラがPATHにあれば SIMUTRANS_COMPILER_BIN は省略できます。SIMUTRANS_COMPILER でg++実行ファイル、SIMUTRANS_PROBE で生成先を指定できます。既定の生成先は .validation/ です。Windows以外ではPowerShell 7(pwsh、POWERSHELL で変更可)が必要ですが、ネイティブ検証の実行確認はWindowsのみです。
ゲーム全体の検証は、追加で SIMUTRANS_RUNTIME_DATA と SIMUTRANS_PAKSET に実行用データ・paksetを指定し、CMake/Ninjaを用意して powershell -NoProfile -File tools/validation/run-world-probe.ps1 を実行します。再現条件と検証の限界は 試作の検証記録 を参照してください。
npm run build で生成する dist/ をHTTPで配信します。npm run preview でローカル確認できます。アセットとWorkerは相対パスで、配信先のサブディレクトリ名に依存しません。file:// で直接開く運用には対応しません。
GitHub Pagesはリポジトリの Settings → Pages → Source を GitHub Actions に設定します。mainへのpush、またはmainを指定したCIワークフローの手動実行で、単体・ブラウザ回帰・配信成果物の検証後に dist/ のみを公開します。依存取得はHTTPSを使用し、docs-lintも固定コミットのアーカイブから取得するためSSH鍵は不要です。
npm run benchmark:cpu は256・512・1024四方の造成をウォームアップ後5回計測し、.validation/cpu-performance.json を保存します。push・PRのCIでも実行し、結果を30日間保存します。現在は計測記録のみで、速度の閾値による失敗判定はありません。
実機での操作計測はPowerShellで実行します。
$env:VALIDATE_OPERATIONS='1'
npm run test:browser -- --grep 'operation performance' --project chrome連続ドラッグ中の1更新ごとのCPU待ち時間は、VALIDATE_INTERACTION=1 を設定して npm run test:browser -- --grep 'continuous sculpting' --project chrome で計測できます。.validation/interaction-*.json に初回・中央値・95%点と処理内訳を保存します。--repeat-each 3 で試行を分け、INTERACTION_BASELINE_REF に比較元コミットSHAを指定すると、API互換のある旧版の地形処理・格子更新・地形描画・水面モジュールを同じ画面操作で比較します。セッションAPIや分割水面モジュール追加前のコミットは差替え対象にできません。APIが異なる版は、それぞれのチェックアウトで計測してJSONを保存・比較してください。これはローカルGPUでの応答計測で、操作全体の時間や見た目のfpsとは別の指標です。従来の操作計測JSONにも更新内訳を追加保存します。ブラシは INTERACTION_RADIUS(1〜40)、INTERACTION_AMOUNT(1〜8)、INTERACTION_TOOL(raise/lower)で変更でき、JSONに条件と水面処理の時間も保存します。例えば40・8・lowerは海岸線が変化する広い掘削の検証です。
ローカルGPUで4096四方のドラッグ目標を検証する場合は、追加で $env:DRAG_BUDGET_MS='1000' を設定します。1秒の判定は指定時だけ有効です。標準は1024・2048・4096四方です。PERF_SIZES 環境変数でカンマ区切りのサイズを指定できます。GitHub Actionsの browser-performance は手動起動でサイズを選択し、Playwright Chromiumで計測します。通常ランナーの描画結果をローカルGPUの速度と直接比較しないでください。CIと同じ専用設定は npx playwright install chromium 後に npm run benchmark:browser で実行できます(VALIDATE_OPERATIONS=1 が必要)。
mainへのpushとmainでの手動ブラウザ計測が成功すると、性能記録Issue に結果表とJSONをコメントします。PRからは投稿しません。成果物が期限切れになっても、コメント内の生データから再集計できます。同一の計測種別・CI実行ID・再実行番号は二重投稿せず、再実行番号が異なる測定は別記録として残します。
GitHub CLIでリポジトリを読める認証を済ませてから npm run performance:export を実行すると、公式CIボットの記録を取得し .validation/performance-history.csv へ集約します。引数で出力先を変更できます(例: npm run performance:export -- .validation/history.csv)。1行は1実行・サイズ・操作で、単位はmsです。CPU/ブラウザ、計測バージョン、環境を分けて比較してください。数値は平均せず、生の各試行から中央値を再計算します。ローカル計測は識別情報を保存しますが、自動ではIssueへ投稿しません。
持続負荷の計測は npm run benchmark:sustained -- --project sustained-chrome で実行します。ローカルのChromeで、既定は4096四方・ブラシ半径40・強さ1、60秒かつ最低12サイクルです。造成・非同期履歴退避を繰り返し、3サイクルごとにUndo/Redo後の地形と格子をダイジェストで照合します。通常CIでは実行しません。条件変更の例:
$env:SUSTAINED_SIZE='4096'
$env:SUSTAINED_SECONDS='60'
$env:SUSTAINED_CYCLES='12'
$env:SUSTAINED_RADIUS='40'
npm run benchmark:sustained -- --project sustained-chromeサイズは256〜8192、秒数は1〜900、最低サイクル数は2〜300、半径は1〜256(40超は検証時に画面の上限設定も変更)、SUSTAINED_AMOUNT は1〜8です。最大サイクル数は SUSTAINED_MAX_CYCLES(最低サイクル数〜10000、既定3000)で指定でき、その回数で打ち切り、指定時間未達なら未完了として記録します。この計測だけ履歴件数上限を最大サイクル数に合わせ、RAM 64 MiB・保存量512 MiBの予算は維持します。.validation/sustained-*.json にソースSHA・GPU・操作別時間・フレーム間隔・同期履歴登録時間・保存量・参考JSヒープを残し、途中失敗時も取得済みの記録を保存します。SUSTAINED_TERRAIN は flat(既定)・coast(複雑な海岸線)・slopes(標高範囲を含む斜面帯)を選べます。--project sustained-edge でEdge、--repeat-each 2 で独立した複数試行を実行します。SUSTAINED_PATTERN=raise-smooth は盛土と平滑化を交互に、SUSTAINED_PATH=reversal は同じ9点で折返しを行います。SUSTAINED_SMOOTHING_RADIUS(1〜16)と SUSTAINED_SMOOTHING_MODE(surface/slope)も記録します。平滑化が無変更だったサイクルは件数とドラッグ時間を別に記録し、地形・格子が不変であることを確認してUndo/Redo照合を省きます。操作計測終了後にPNG書出・再取込を行い、標高と外周格子を照合します。この往復時間は workloadElapsedMs に含めません。前半/中盤/後半はサイクル数による三分割です。時刻基準はJSONへ明記します。
フレーム間隔はメインスレッドの応答指標で、描画fpsではありません。静止中は描画を休止します。JSヒープはGPU・Worker・多くのArrayBufferを含まない参考値で、総メモリやリークの有無を示しません。操作全体にはテストドライバの待機時間も含むため、同期処理時間と分けて評価してください。
画像変換の計測は npm run benchmark:image-io で実行します。4096・8192四方の平坦地形についてBMP/PNGのWorker書出・読込・正規化を測り、.validation/image-io-chrome.json へ段階別時間・フレーム間隔・配列サイズの部分見積もりを保存します。通常CIでは実行しません。IMAGE_IO_BROWSER=msedge または chromium でブラウザを変更できます。ファイル選択・確認待ち・最終的な地形描画反映は計測外です。配列見積もりは同時使用量や総メモリの実測ではなく、PNG圧縮内部・GPU・Blobコピーなどを含みません。BMPの出力行と出力ファイルは同じ配列なので合算できません。
ドキュメントは docs/README.md の規約に従います。初期調査は docs/records/、意思決定は docs/adr/ に保存し、調査の続報は新しい記録として追加します。
水面表示の自動CPU配列予算はマップ面積に応じて16〜64 MiB(4096四方で16 MiB、8192四方で64 MiB)です。画面から16〜256 MiBの固定予算も選べます。GPU側のコピーと更新時の一時配列は別途必要です。水面の大メモリ検証は VALIDATE_LARGE_WATER=1 を設定し、node --experimental-strip-types --test tests/water-surface.test.ts tests/water.test.ts で実行できます。