Files
healer-man/scripts/dungeon-pipeline/optimize-environment.mjs
T
2026-08-14 15:56:39 -04:00

73 lines
2.7 KiB
JavaScript

import { spawn } from "node:child_process";
import { stat } from "node:fs/promises";
import path from "node:path";
import { exists, loadRecipe, projectRoot, readJson, workRoot, writeJson } from "./lib.mjs";
function runCli(args) {
const cli = path.join(projectRoot, "node_modules/@gltf-transform/cli/bin/cli.js");
return new Promise((resolve, reject) => {
const child = spawn(process.execPath, [cli, ...args], { cwd: projectRoot, stdio: "inherit", windowsHide: true });
child.once("error", reject);
child.once("exit", (code) => code === 0 ? resolve() : reject(new Error(`gltf-transform exited with code ${code}.`)));
});
}
function compressKtx2(file) {
const compressor = path.join(projectRoot, "scripts/asset-pipeline/compress-ktx2.mjs");
return new Promise((resolve, reject) => {
const child = spawn(process.execPath, [
compressor,
file,
"--concurrency",
"1",
"--jobs",
"2",
], { cwd: projectRoot, stdio: "inherit", windowsHide: true });
child.once("error", reject);
child.once("exit", (code) => code === 0
? resolve()
: reject(new Error(`KTX2 compression exited with code ${code}.`)));
});
}
export async function optimizeDungeonEnvironment(slug) {
await loadRecipe(slug);
const directory = path.join(workRoot, slug, "staging", "environment");
const conversionFile = path.join(directory, "conversion-report.json");
if (!await exists(conversionFile)) return { status: "blocked", dungeonId: slug, blockers: ["Run dungeon:convert first."] };
const conversion = await readJson(conversionFile);
const source = path.join(directory, conversion.visual.file);
if (!await exists(source)) return { status: "blocked", dungeonId: slug, blockers: ["The lossless visual GLB is missing."] };
const optimized = path.join(directory, `${slug}-visual.optimized.glb`);
await runCli([
"optimize",
source,
optimized,
"--compress",
"meshopt",
"--meshopt-level",
"high",
"--instance",
"true",
"--instance-min",
"3",
"--texture-size",
"2048",
]);
await compressKtx2(optimized);
const report = {
schemaVersion: 1,
dungeonId: slug,
status: "review-required",
source: { file: path.basename(source), size: (await stat(source)).size },
optimized: { file: path.basename(optimized), size: (await stat(optimized)).size },
compression: "meshopt+ktx2",
commands: [
"gltf-transform optimize --compress meshopt --meshopt-level high --instance true --instance-min 3 --texture-size 2048",
"node scripts/asset-pipeline/compress-ktx2.mjs <optimized.glb> --concurrency 1 --jobs 2",
],
};
await writeJson(path.join(directory, "optimization-report.json"), report);
return report;
}