作りたいアイテムと毎分レートを入れるだけで、必要なレシピ・建物数・電力・原料を計算する 日本語の生産計画ツール(ゲーム Satisfactory の非公式ファンツール)。 ブラウザだけで動き、インストールもアカウント登録も要らない。
- 最適化して出す: 線形計画法(glpk.js)で「資源効率 / 電力最小 / 建物最小」から選んで解く。 総当たりの手計算ではなく、副産物の再利用や循環レシピも含めて一発で出る
- 12言語: 画面もアイテム名も母語で読める。アイテム名・レシピ名・建物名は ゲーム公式のローカライズをそのまま使うので、ゲーム内の表記と1文字も違わない(手訳なし)
- Excel出力: サマリー・生産ステップ・原料・収支・物流・レシピの6シートを .xlsx で書き出す
- フローチャート: 原料から最終製品までの流れを閲覧専用の図で追える。 ベルト/パイプ1本で運びきれない線はボトルネックとして赤く出る
- 細かい条件: 代替レシピの取捨、原料上限(マップのノード数由来)、製造クロック上限、 採掘クロック、サマースループ、既に手元にあるアイテムの持ち込み、産出の最大化
- 保存と共有: 入力はブラウザ内(IndexedDB)に保存。URL にも埋め込めるので、 開いた人はそのまま同じ計算結果を見られる
初めて開いたときは空状態に 「例から始める」(鉄板ライン / リサイクルでプラスチック増産 / ヘビー・モジュラー・フレーム工場)が出る。押すと入力が入って、そのまま結果まで見られる。
画面右上のセレクタでいつでも切り替えられる(選択はブラウザに保存される)。 初回はブラウザの言語設定から自動で選ばれ、対応が無い言語では英語になる。
日本語 (ja) / English (en) / Deutsch (de) / Français (fr) / Español (es-ES) / Português do Brasil (pt-BR) / Русский (ru) / 简体中文 (zh-Hans) / 繁體中文 (zh-Hant) / 한국어 (ko) / Polski (pl) / Türkçe (tr)
アイテム・レシピ・建物の名前はどの言語でもゲーム同梱の公式ローカライズから生成しており
(src/data/names.<locale>.json)、その言語に訳が無いものだけ英語名になる。
計算結果・保存データ・共有URLは言語に依存しない(同じURLをどの言語で開いても同じ計算になる)。
UI文言はAI翻訳をベースにしています。母語話者から見て不自然な箇所があれば、 Pull Request か Issue で指摘してください。1語の直しでも歓迎します。
- 直すファイル:
src/i18n/locales/<locale>.ts(1言語=1ファイル。キー構成は変えない) - アイテム名・建物名などのゲーム用語は直接書かない。
{{Desc_IronPlate_C}}のような トークンのまま残してください(公式訳に自動で置き換わります) - 確認:
npm run typecheck && npm test
The UI strings started from AI translation. If something reads unnatural to a native speaker, please open a pull request or an issue — even a single word is welcome.
- Edit
src/i18n/locales/<locale>.ts(one file per language; keep the key structure unchanged) - Never write item/building names directly. Leave the
{{Desc_IronPlate_C}}tokens in place; they are replaced with the official game translation at runtime - Verify with
npm run typecheck && npm test
公開前に差し替える(画像は docs/screenshots/ に置き、ここから相対パスで参照する)。
- 目標入力と結果サマリー … 未撮影
docs/screenshots/summary.png - 生産ステップ表 … 未撮影
docs/screenshots/steps.png - フローチャート … 未撮影
docs/screenshots/flow.png - Excel出力 … 未撮影
docs/screenshots/excel.png
Phase 6(保存・共有)+クロック / サマースループ / 床面積 / 発電計画の対応まで完了。 ブラウザで目標を入力すると結果が読め、6シートの .xlsx が落とせて、 原料→最終製品の流れをフローチャートで追える。 製造・採掘のクロック、サマースループ、概算床面積も画面と Excel の両方に出る。 発電計画(目標MWから発電機の台数と燃料チェーンを逆算)も同じ LP に載っている。
| Phase | 内容 | 状態 |
|---|---|---|
| 1 | データパイプライン(Docs.json → 正規化JSON) | 完了 |
| 2 | 計算エンジン(LPソルバー選定+実装) | 完了 |
| 3 | 結果テーブル | 完了 |
| 4 | Excel出力 | 完了 |
| 5 | 閲覧専用グラフ | 完了 |
| 6 | プランの保存・共有(IndexedDB / URL) | 完了 |
| 7 | クロック設定・サマースループ・床面積の概算 | 完了 |
| 8 | 発電計画(発電機と燃料チェーンを LP に統合) | 完了 |
npm install
npm run build-data # 初回は data-source/ の Docs を自動ダウンロードして正規化JSONを生成| コマンド | 内容 |
|---|---|
npm run fetch-docs |
公式 Docs のミラーを data-source/ に取得(-- --force で再取得) |
npm run build-data |
data-source/*.json → src/data/{items,recipes,buildings,extractors,logistics,meta}.json を生成 |
npm run fetch-icons |
アイテム/建物のアイコンを public/icons/ に取得(-- --force で再取得)。出典と撤去手順は public/icons/SOURCES.md |
npm test |
vitest(スキーマ整合性・既知値・日本語名の検証) |
npm run typecheck |
tsc --noEmit |
npm run dev |
Vite 開発サーバ |
npm run build |
型チェック+本番ビルド |
ゲームがアップデートされたら npm run fetch-docs -- --force && npm run build-data && npm test の
3手でデータを更新できる(データソースの記録は data-source/DATA_SOURCES.md)。
data-source/ Docs.json のミラー(gitignore。DATA_SOURCES.md だけコミット)
public/icons/ アイテム/建物のアイコン(ゲームアセット。SOURCES.md に出典と撤去手順)
scripts/
fetch-docs.ts Docs のダウンロード
fetch-icons.ts アイコンのダウンロード(公式Wiki。無くてもアプリは動く)
docs-parse.ts エンコーディング判定・Unreal文字列パース(単体テスト対象)
build-data.ts 正規化パイプライン本体
src/data/
types.ts Item / Recipe / Building / Extractor / Generator / Belt / Pipe のスキーマ定義
constants.ts ゲーム係数(電力指数・純度倍率・液体1000倍単位など)を一元管理
map-limits.ts マップの資源ノード数と最大採取レート(Docsに無いので手写し+出典)
index.ts アプリからの参照口(ID索引・レート換算)
*.json 生成物(コミットする)
src/solver/
types.ts SolveInput / Solution(v0 §4.2・§4.4)
lp.ts ソルバー非依存のLPモデル表現+CPLEX LP書き出し
glpk-backend.ts glpk.js(WASM) バックエンド。Node/ブラウザ両対応
model.ts レシピ集合 → LPモデルの組み立て
solve.ts 求解と Solution の組み立て・実行不能診断
overclock.ts オーバークロック / サマースループ の後処理
logistics.ts ベルト・パイプの本数換算
extraction.ts 原料レート → 採掘機の台数・純度別ノード割当・採掘電力
src/plan/
aggregate.ts 画面とExcelで共有する集計(建てる台数・機械種別グループ・建設コスト合成)
flows.ts アイテムフローの列挙・搬送手段の解決(Excelの物流シートとグラフの共通元)
graph.ts 解 → フローチャートのノード/エッジ(描画ライブラリ非依存の純データ)
power-filter.ts 「発電を隠す」の判定(発電機+発電専用チェーン。表示だけの絞り込み)
src/export/
excel.ts Excel(.xlsx)出力。6シートの組み立て・書式・ファイル名・ダウンロード
src/store/
planner.ts 入力状態と解(zustand)。入力変更で200msデバウンス再計算
src/ui/
text.ts UI 文言(日本語)を集約
format.ts 数値フォーマット(レート小数2位・台数小数4位)
icons.ts ID → アイコン画像パスの解決(無ければ null=文字だけ表示)
ItemIcon.tsx アイコン1つ分の <img>(欠落・読み込み失敗時は何も描かない)
Sidebar.tsx 入力(目標 / 目的関数 / 発電計画 / クロック / 採掘設備 / 代替レシピ / 原料上限 / 物流 / Excel出力)
PowerPanel.tsx 発電計画の入力(発電方式の許可・使う燃料の選択・目標発電量・工場の消費を賄う)
ResultView.tsx 結果タブ(サマリー / 生産ステップ / 原料 / アイテム収支 / フローチャート)
PowerFilterToggle.tsx 「発電を隠す」のチェックボックス(ステップ表とフローチャートで共有)
ExportPanel.tsx プラン名の入力とExcelダウンロード(exceljsはクリック時に動的import)
FlowChart.tsx 閲覧専用フローチャート(React Flow。タブを開いたときに遅延import)
flow-layout.ts PlanGraph → React Flow のノード/エッジ(寸法・線種・ラベル)
elk-layout.ts elkjs 呼び出し(Worker優先・失敗時はメインスレッドに自動フォールバック)
elk-layout.worker.ts レイアウト計算のWorker本体
docs/
solver-benchmark.md ソルバー選定の記録(glpk.js vs highs-js)
bench/ ベンチ用スクリプト(tsconfig の対象外)
tests/ vitest
import { solveProduction } from './src/solver/index.ts'
const result = await solveProduction({
targets: [{ item: 'Desc_IronPlate_C', ratePerMin: 60 }],
// enabledRecipes 省略 = 代替レシピを除く全レシピ
// resourceLimits 省略 = マップ上限(map-limits.ts)
})
if (result.status === 'optimal') {
result.steps // レシピ別の台数・電力・入出力レート
result.rawResources // 原料の使用量と上限比率
result.byproducts // 余剰(副産物)
} else {
result.reasons // 実行不能の原因(不足している原料・作れないアイテム)
}- 循環レシピ(リサイクル・プラスチック/ゴム)を正しく解ける。 副産物の再利用も 収支制約で自動的に相殺されるので二重計上しない
- 目的関数は「原料 / 電力 / 台数」の加重和。
weightsで切り替える - 原料の相対コストの既定は
'scarcity'(マップ上限が少ない資源ほど高コスト)。 一律だと「変換機で硫黄から石灰岩を作る」ような解が出るため - 稼働台数は連続値。整数台+クロックへの割り当ては
planClocks()が後処理で出す - 採掘側(採掘機の台数・純度別ノード・採掘電力)は
planExtraction(solution, { clock })。 既定は採鉱機 Mk.3・クロック100%で、純度の高いノードから埋める。端数の1台だけ アンダークロック扱いで電力を計算する(資源井戸は加圧機の台数を平均サテライト数から概算)
maxClock(1 = 100%、最大 2.5)は LP を変えない。稼働台数は常にクロック100%換算のまま出し、
後処理で 建てる台数 = ceil(稼働台数 / maxClock) → 実クロック = 稼働台数 / 建てる台数 を決める。
これに応じて建設コスト・パワーシャード(powerShardsForClock)・消費電力が変わる。
電力はクロックに対して超線形(基本電力 × クロック^powerExponent、指数 ≒ log2(2.5))なので、
クロックを上げると台数は減るが総電力は増える。解には2種類の電力が入る:
powerMW/totalPowerMW… クロック100%換算。LP の目的関数と同じ基準clockedPowerMW/totalClockedPowerMW… クロックとサマースループを適用した実値。画面と Excel の主表示
somersloops(既定 0)に 1 以上を渡すと、maxSomersloops > 0 の建物のレシピについて
フル装着バリアントの変数(xs:<recipeId>)が LP に増える。
- 産出のみ2倍・消費は据え置き・電力は
基本電力 × (1 + 使用数/最大数)^somersloopPowerExponent(既定 4倍) - 制約は1本だけ:
Σ(バリアント稼働台数 × その建物のスロット数) <= somersloops - 通常変数と併存するので、サマースループが足りない分は同じレシピの通常ステップが埋める
- 部分装着(フル未満)はスコープ外。装着数を連続変数にすると産出倍率が変数になって LP が非線形になり、装着数ごとに変数を分けるとレシピ数 × スロット数だけ変数が増えて 求解時間と UI の複雑さに見合わないため。フル装着が最も産出/建物比が良いので、 「サマースループを使う」という意思決定に対しては十分な近似になる
- 制約はクロック100%換算の稼働台数に張る。一方、使用数の表示は「建てる台数 × スロット数」
(実際に挿す個数)なので、両者はクロックと丸めの分だけズレる:
- 端数を切り上げるぶん必要数が上限を超えることがある (例: 1.5台ぶんを 4スロットの建物で回す → 2台 × 4 = 8個 > 上限6)。サマリーに警告を出す
- 逆にクロック上限を上げると台数が減るので、実際に挿す個数は上限より少なくなる (例: 同じ1.5台ぶんを250%上限で回すと1台 = 4個)。この場合、制約が保守的になり 「余ったサマースループを活かしきれない」ことがある。まずクロック上限を決めてから サマースループ数を調整するのが実用上の使い方
somersloops: 0のときはバリアント変数も容量制約も作らないので、LP は従来と1変数も違わない (tests/somersloop.test.tsで回帰を固定)
工場が使う電力を賄う発電所を、燃料の生産チェーンごと同じ LP で解く。
発電機は「燃料(+水)を消費して電力(MW)を産出する変数」(g:<建物ID>:<燃料ID>)として足す。
燃料はアイテム収支の制約に入るので、石炭発電なら石炭の採掘、燃料式なら原油の精製、
原子力ならウラン燃料棒の製造までが1回の求解で同時に決まる。
await solveProduction({
targets: [{ item: 'Desc_IronPlate_C', ratePerMin: 60 }],
power: {
generators: ['Build_GeneratorCoal_C'], // 許可する発電方式(既定は空=発電計画なし)
fuels: { Build_GeneratorCoal_C: ['Desc_CompactedCoal_C'] }, // 使う燃料の絞り込み(省略=全燃料)
targetMW: 300, // 総発電量の下限
coverFactoryPower: true, // 製造建物の消費を賄う(自己消費の循環も LP が解く)
},
})fuels は発電機ごとの燃料の許可集合。キーの無い発電機は全燃料許可(省略すれば
従来と同じ LP になる)。空配列にした方式は変数を1本も作らないので、
「石炭発電機は圧縮石炭だけ」「原子力はウラン燃料棒だけ(プルトニウムチェーンを組まない)」
といった指定ができる。選んだ燃料をどうしても用意できない構成は、実行不能の原因として
その燃料名を挙げて報告する(findUnusableGenerators)。
画面(PowerPanel)では、実プレイで1つの発電方式に流す燃料が1種類であることに合わせて
方式をオンにした時点では燃料は未選択にしてある(u の意味は保存形式 v6 を参照)。
ソルバー側の「キーが無い=全燃料許可」は、v5 以前の保存プラン・共有URLを
そのまま読むための後方互換として残している。
廃棄物(ウラン廃棄物・プルトニウム廃棄物)を産出するレシピはゲームに存在せず、
燃料棒を燃やしたときの副産物としてしか得られない。そこで副産物を出す発電機 × 燃料
(generators.json の byproduct から導く。ID はハードコードしない)は、発電計画の有無に
関係なく常に LP の変数にする。発電計画で許可した組み合わせは従来どおり制限なし、
それ以外は需要駆動(GeneratorVariant.demandDriven)で、副産物ごとの行
byproduct:<item>…Σ(需要駆動の副産物レート × g) - Σ(レシピの消費 × x_r) <= 目標産出
により「副産物が消費される量までしか稼働できない」。プルトニウム・ペレットや FICSONIUM を
目標にすれば発電計画なしでも解け、原子力発電所が廃棄物の需要ぶんだけ結果に並ぶ
(tests/generator-byproduct.test.ts)。到達可能性の判定(findUnreachableTargets /
findUnusableGenerators)もこの変数を副産物の供給源として数える。
需要駆動の発電機の発電量は、発電計画が無効なら Solution.powerGeneration に報告するだけで
制約には使わない。発電計画が有効なら目標・自給の行に数える(石炭だけを許可した計画でも、
廃棄物のために回る原子力の電力ぶんだけ石炭発電機が減る)。ただし数えたまま1回で解くと
LP が「再処理を余分に建てて廃棄物の需要を作り出し、許可していない原子力を発電に流用する」
抜け道を見つけるので、solve.ts は2段階で解く: 1段目は需要駆動の発電量を数えずに
副産物の需要ぶんの台数を確定し、2段目はその台数に固定して(副産物から派生するアイテムの
余りも1段目の値までに抑えて)発電量を数え直す。
制約は電力専用の行を2本張る(電力を疑似アイテムにはしない。存在しないアイテムIDを 作ると表・グラフ・Excel が名前を引けなくなるため):
power:target…Σ(発電量_g × g) >= targetMWpower:cover…Σ(発電量_g × g) - Σ(消費電力_r × x_r) >= 0右辺ではなく左辺に消費が入るので、発電のために増えた建物(燃料の精製・ウラン加工など)の 消費も自動的に含まれる。「発電所を建てる → 消費が増える → もっと発電所が要る」の循環は LP が同時に解く(反復計算は不要)
収録する発電機は generators.json(npm run build-data の生成物):
| 発電機 | 発電量 | 燃料(消費レート) | 水 | 副産物 |
|---|---|---|---|---|
| 石炭発電機 | 75 MW | 石炭 15/min ・ 圧縮石炭 約7.14/min ・ 石油コークス 25/min | 45 m³/min | — |
| 燃料式発電機 | 250 MW | 燃料 20 ・ ターボ燃料 7.5 ・ ロケット燃料 約4.17 ・ イオン化燃料 3 ・ 液体バイオ燃料 20(m³/min) | — | — |
| 原子力発電所 | 2500 MW | ウラン燃料棒 0.2/min ・ プルトニウム燃料棒 0.1/min ・ フィクソニウム燃料棒 1/min | 240 m³/min | ウラン廃棄物 10/min ・ プルトニウム廃棄物 1/min |
数値はすべて Docs.json 由来(ハードコードしない)。燃料の消費レートは
発電量MW × 60 ÷ 燃料のエネルギー量MJ(mPowerProduction と mEnergyValue)、
水は 発電量MW × mSupplementalToPowerRatio × 60 ÷ 1000、
副産物は 燃料の消費レート × mByproductAmount で求めている。
収録しないもの(意図的):
- バイオマスバーナー … 燃料(葉・木材・菌糸)をマップから手で拾って投入する前提で、 生産チェーンとして自動供給できない
- 地熱発電機 … 出力が間欠変動する(
mVariablePowerProductionFactor)ので定常レートの LP に載らない
スコープ外(現時点):
- 発電側のオーバークロック。発電機のクロックは常に100%固定で、
maxClockの影響を受けない。 端数の稼働台数は切り上げて建て、残りは部分負荷(clockSpeed < 1)として表示する (ゲーム内でも需要に応じて自動で負荷が下がるので、この扱いが実態に近い) - 採掘設備の電力。採掘計画は LP の外(
planExtraction)で決まるので、coverFactoryPowerの 対象は製造建物だけ。採掘機ぶんは画面の「総消費電力」で別途確認する - 発電機の消費電力は 0 なので、
totalPowerMWは従来どおり「消費」だけを表す。 発電量はSolution.powerGeneration(総発電量・目標・台数・燃料の消費)と 各ステップのpowerProductionMWに入る generatorsが空、またはtargetMWもcoverFactoryPowerも無いときは電力の制約行を作らない。 LP に載るのは副産物を出す発電機の需要駆動の変数だけで、廃棄物を使わない計画の解は 従来と変わらない(tests/power.test.tsで回帰を固定)
npm run dev で起動。左が入力、右が結果タブ。
- 入力: 目標産出(日本語名のインクリメンタル検索)/ 既にあるアイテム(手持ち・別工場からの供給。 コスト0で投入され、原料の採掘より優先して使われる)/ 目的関数プリセット(資源効率・電力最小・ 建物最小)/ 発電計画(発電方式の許可・目標発電量MW・工場の消費電力ぶんを賄う) / 製造クロックの上限(10〜250%)と使えるサマースループの数 / 固体ノードの採掘機 Mk と採掘クロック(100/150/200/250%) / 代替レシピの一括+個別ON・OFF / 原料上限の上書き / 搬送手段(ベルト・パイプの Mk)/ プラン名と Excel ダウンロード
- 目標産出の各行は「レート指定」と「最大化」を切り替えられる。最大化は同時に1行だけで、
他のレート指定を満たしたうえで原料上限まで作れるだけ作る(
SolveInput.maximize)。 上限のない資源(水など)だけで作れる構成は解が無限大になるので、非有界として検出し 実行不能の表示に「原料上限を入れるか、レート指定に切り替える」ヒントを出す - 結果: サマリー(総電力の幅表示+製造・採掘・パワーシャード、総発電量と目標・燃料の消費、 サマースループの使用数と上限、 概算床面積とファウンデーション枚数、建物数、建設コスト、シンクポイント、副産物)/ 生産ステップ(機械種別グルーピング・「N台 @ X%」・シャード・サマースループ・発電量)/ 原料(上限比率・採掘機台数・純度別ノード・シャード)/ アイテム収支(余剰・不足を色とラベルの両方で表示)
- シャード列・サマースループ列は実際に使うときだけ出す(既定の設定では表を細く保つ)
- 解けないときは Phase 2 の診断結果(不足している原料と量)を日本語で表示する
建物の外形は Docs.json の mClearanceData(建設クリアランス)から取り、buildings.json の
footprint(幅・奥行・高さ・設置面積)に入れている。CT_Soft(コンベア接続などの柔らかい
クリアランス)と ExcludeForSnapping(補助クリアランス)の箱は外し、残りの箱を
平行移動・回転を適用したうえで和を取る。1.1.x では全23建物が Docs から取れるが、
取れなくなった場合に備えて scripts/build-data.ts の FOOTPRINT_FALLBACKS(Wiki 既知値)を用意してある。
概算床面積 = Σ(建てる台数 × 1台の設置面積) × AISLE_AREA_FACTOR(通路係数 1.5・constants.ts に根拠つき)。
ファウンデーションは 8m × 8m = 64m² で割った切り上げ枚数。あくまで概算で、
縦積みや詰め方で実際の広さは変わる旨を画面と Excel の両方に注記している。
サイドバー下部の「Excelダウンロード」で、現在の解を .xlsx に書き出す(src/export/excel.ts)。
ファイル名は satisfactory-plan_<プラン名>_<YYYYMMDD>.xlsx(プラン名未入力なら plan)。
| シート | 内容 |
|---|---|
| サマリー | プラン名・目標産出(最大化した行は要求欄が「最大化」+最大産出レート)・電力(製造/採掘/合計)・クロックとサマースループ(上限・クロック適用後の電力・シャード・使用数)・発電計画(総発電量/目標/差引/台数/燃料の消費)・建物数・床面積の概算・必要原料・既保有アイテムの投入(投入量と使用量)・シンクポイント・副産物・有効な代替レシピ |
| 建物リスト | 機械種別ごとのレシピ・稼働台数・建てる台数・クロック・パワーシャード・サマースループ・電力・発電量・寸法(幅/奥行/高さ/設置面積)・投入/産出 |
| アイテム収支 | 産出/消費/外部供給/差分。不足=赤系・余剰=青系の塗り+状態ラベル |
| 原料 | 必要レート・マップ上限比率・採掘設備の台数・純度別のノード割当・パワーシャード・採掘電力 |
| 建設コスト | 製造建物と採掘設備の建材合計 |
| 物流 | 各フローのベルト/パイプ換算(選択中の Mk での必要本数・使用率) |
- サマリー以外はヘッダー行を固定+オートフィルタ付き。列幅は内容に合わせて自動調整
- 数値は必ず数値セル(レート・電力は小数2位、稼働台数は小数4位の表示形式)。 合計行はフィルタで隠れないようフィルタ範囲の外に置く
- 生成は Node / ブラウザ共通。保存部分だけ環境で分岐する(テストは
tests/excel.test.tsで 書き出した .xlsx を読み戻して検証している) - exceljs はバンドルが重いのでダウンロード時に動的 import する(初期表示には載らない)
- フローの列挙(原料供給 / 各ステップの投入・産出)と搬送手段の解決は
src/plan/flows.tsに 一本化してあり、物流シートとフローチャートのエッジは必ず同じ数字になる
発電計画を有効にすると発電機と燃料チェーンが結果に混ざる。工場の構成だけを見たいとき用に、 生産ステップ表とフローチャートの上部に「発電を隠す」チェックボックスを出す (両タブで状態を共有・既定オフ・保存しない。発電計画が無効な解では出さない)。
- 判定は
src/plan/power-filter.ts。目標産出を作るステップから投入方向へ不動点まで遡って 「工場側」を確定し、そこに入らなかったステップ(=発電機と、燃料にしか流れないステップ)を隠す。 逆向き(発電側を伸ばす)だと循環レシピが確定しないのでこの向きにしている - 種を「目標産出」に限るのが肝。発電用の燃料精製はポリマー樹脂を副産物に吐くが、これは 捨てているだけなので「副産物が出ている=工場」にすると発電専用の精製所が丸ごと残ってしまう
- 原料供給ノードは、工場側の消費者が1つも無いときだけ隠す(原油をプラスチック工場と 燃料式発電が共有していれば原油は残る)。レートは解の値のままで、原料タブと数字がズレない
- 計算・サマリー・原料・収支・Excel は一切変えない(隠しても数字の網羅性は保つ)
結果タブの「フローチャート」。ソルバー結果から自動生成する読み取り専用の図で、 手動編集はしない(仕様書 §9 / やらないリスト)。
- ノード: 原料供給(採掘)/ 既保有アイテムの持ち込み(紫の破線枠+「既保有」ラベルで採掘と区別)/ 生産ステップ(レシピ名・機械種別・建てる台数とクロック・電力・サマースループ使用数・投入/産出)/ 出力(目標産出は橙、副産物は無彩色)
- 発電機も生産ステップのノードとして並ぶ。ただし電力のエッジは張らない (ゲーム内の電力網は1本にまとまっていて、どの発電機がどの建物へ、という線に意味がないため)。 燃料と水の流れだけを線で描き、発電量はノードの中に「発電 → N MW」と書く
- エッジ: アイテムフロー。ラベルは
鉄板 60.00/min。固体=実線・液体=破線・気体=点線で、 色が判別できなくても形で区別できる(カラーユニバーサル) - ボトルネック: サイドバーで選んだベルト/パイプ 1本の上限を超えるフローを赤の太線にし、
ラベルに「要 N本」を出す(
src/plan/graph.tsのutilization > 1) - レイアウト: elkjs の layered(左→右)。計算は Web Worker で回すのでパン/ズームが固まらない。 Worker が使えない環境ではメインスレッド版に自動フォールバックする
- ラベルの位置も elkjs 任せ。文字幅を推定した矩形を
labelsとして渡し、返ってきた座標に そのまま置く(React Flow 既定の「線の中点」だとラベル同士・ノードと重なって読めない)。 線も elk の経路をそのまま描くのでラベルと線がズレない。重なりゼロはtests/flow-layout.test.tsが矩形の重なり面積で検証している - 操作: パン / ズーム / ミニマップ / 全体フィットのみ。ドラッグ移動・接続・削除は無効
- エッジの分岐は「生産量 × 消費量 ÷ 総量」の按分。アイテムごとに
入ってきた量と出ていく量が必ず一致する(
tests/graph.test.tsで検証)
- 液体・気体は Docs 内で 1000倍の内部単位。正規化時に 1/1000 して m³ に統一済み。
固体は個数のまま。レート換算は
amount * 60 / durationSec - アイテム名・レシピ名・建物名は
{ ja, en }の両方を保持(日本語は公式ローカライズから取得、手訳なし)。 ただし公式 ja ローカライズ自体が未訳のものだけはscripts/build-data.tsのJA_NAME_OVERRIDESで補い、meta.untranslatedJaNamesに記録する (1.1.x ではRecipe_Alternate_PolyesterFabric_Cの1件のみ) - 対象は製造系レシピ+生産系建物のみ。装飾・車両などは除外(除外ルールは
scripts/build-data.tsのコメント参照) - 採掘・抽出はレシピとして定義されていないため、建物の
mItemsPerCycle/mExtractCycleTimeからextractors.jsonを組み立てている(純度倍率はconstants.ts) - 発電もレシピが無いので、
mPowerProductionとmFuel(燃料候補の配列)からgenerators.jsonを組み立てている。燃料の消費レートはアイテムのmEnergyValueから発電量MW × 60 ÷ エネルギー量MJで求める(液体・気体のmEnergyValueは mL あたりなので ×1000) - 建物の外形は
mClearanceDataからfootprint(幅・奥行・高さ・設置面積)を組み立てる。CT_Soft/ExcludeForSnappingの箱は除外し、残りに平行移動と回転を適用して和を取る (製造機 18×20m・組立機 9×16m など公式Wikiの記載と一致することをtests/footprint.test.tsで確認) - ベルト/パイプの速度は
logistics.json(mSpeedは 1/2、mFlowLimitは ×60 で実効値) - マップの資源ノード数・最大採取レートだけは Docs に無いので
src/data/map-limits.tsに Wiki の値を手写ししてある。ノード数から最大レートを再計算して一致することをテストで担保
数値・レシピ・建物の仕様は、Coffee Stain Studios がゲームに同梱している
コミュニティ向け Docs(Satisfactory/CommunityResources/Docs/)が出典。
本リポジトリはそのミラーを取得して正規化JSONに変換しているだけで、Docs 自体はコミットしない。
日本語のアイテム名・レシピ名・建物名は同 Docs の 公式 ja ローカライズをそのまま使っている(手訳なし)。
- 対象バージョン: Satisfactory 1.1.x
- 取得元・バージョン判定の根拠・更新手順:
data-source/DATA_SOURCES.md - マップの資源ノード数と最大採取レートだけは Docs に無いため、公式 Wiki
https://satisfactory.wiki.gg/ の値を
src/data/map-limits.tsに手写ししている(出典コメント付き)
public/icons/ の PNG は ゲーム内アイコン(著作権は Coffee Stain Studios)。
公式 Wiki https://satisfactory.wiki.gg/ から 64px サムネイルとして取得している。
可読性のために引用的に表示しているだけで、再配布の許諾を受けたものではない。
権利者からの要請があれば即座に全削除する(撤去手順とアプリ側の挙動は
public/icons/SOURCES.md。アイコンが無くなっても画面はテキスト表示に戻るだけで壊れない)。
- 求解: glpk.js(GLPK の WebAssembly 版 / GPL-3.0)
- Excel: ExcelJS(MIT)
- 図: React Flow(MIT)/ elkjs(EPL-2.0)
GPL-3.0(LICENSE)。ソルバーに使用している glpk.js(GPL-3.0)に合わせています。 ソースの再配布・改変は GPL-3.0 の条件のもとで自由です。
例外: public/icons/ のゲームアイコン画像は Coffee Stain Studios の著作物であり、
GPL の対象外です(出典と扱いは public/icons/SOURCES.md を参照)。
本ツールは 非公式のファンツールであり、Coffee Stain Studios 社および Satisfactory の 開発・運営元とは一切関係がありません。当ツールに関する問い合わせを権利者に送らないでください。
- Satisfactory およびゲーム内の名称・画像は Coffee Stain Studios の商標・著作物です
- 計算結果はゲームデータに基づく理論値です。実際のゲーム内の挙動・アップデートによる仕様変更との 差異について、作者は一切の責任を負いません
- 非商用・無保証で提供しています