Add configurable area asset budgets
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const { BUDGETS } = require("./stage-manifest");
|
||||
|
||||
function readAreaConfig(file, options = {}) {
|
||||
if (!fs.existsSync(file)) {
|
||||
@@ -23,6 +24,7 @@ function normalizeAreaConfig(raw, options = {}) {
|
||||
const areaDir = path.resolve(outputOverrides.areaDir || path.join(outputRoot, id));
|
||||
const fileStem = outputOverrides.fileStem || id;
|
||||
const compress = normalizeCompressConfig(raw.compress);
|
||||
const budget = normalizeBudgetConfig(raw.budget);
|
||||
const compressedFileStem = outputOverrides.compressedFileStem ||
|
||||
`${fileStem}-compressed-webp${compress.textureSize}${compress.meshopt ? "-meshopt" : ""}`;
|
||||
const pipelineDir = path.resolve(outputOverrides.pipelineDir || path.join(areaDir, "_pipeline"));
|
||||
@@ -92,10 +94,34 @@ function normalizeAreaConfig(raw, options = {}) {
|
||||
officeOverrides: raw.blender?.officeOverrides || raw.blender?.office_overrides || "",
|
||||
},
|
||||
compress,
|
||||
budget,
|
||||
outputs,
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeBudgetConfig(raw) {
|
||||
if (raw !== undefined && raw !== null && (typeof raw !== "object" || Array.isArray(raw))) {
|
||||
throw new Error("budget must be an object");
|
||||
}
|
||||
const value = raw || {};
|
||||
const budget = {
|
||||
glbBytes: megabytesOption(value.glbSizeMb, BUDGETS.glbBytes, "budget.glbSizeMb"),
|
||||
glbNodes: integerOption(value.nodes, BUDGETS.glbNodes, "budget.nodes"),
|
||||
glbImages: integerOption(value.images, BUDGETS.glbImages, "budget.images"),
|
||||
glbTriangles: integerOption(value.triangles, BUDGETS.glbTriangles, "budget.triangles"),
|
||||
glbImageBytes: megabytesOption(value.embeddedImageBytesMb, BUDGETS.glbImageBytes, "budget.embeddedImageBytesMb"),
|
||||
reason: value.reason ?? "",
|
||||
};
|
||||
if (typeof budget.reason !== "string") {
|
||||
throw new Error("budget.reason must be a string");
|
||||
}
|
||||
const loosened = Object.keys(BUDGETS).some((key) => budget[key] > BUDGETS[key]);
|
||||
if (loosened && budget.reason.trim() === "") {
|
||||
throw new Error("budget.reason is required when a budget exceeds the default");
|
||||
}
|
||||
return budget;
|
||||
}
|
||||
|
||||
function requireText(value, key) {
|
||||
if (typeof value !== "string" || value.trim() === "") {
|
||||
throw new Error(`Missing config key: ${key}`);
|
||||
@@ -121,6 +147,22 @@ function numberOption(value, fallback, label, min, max) {
|
||||
return number;
|
||||
}
|
||||
|
||||
function integerOption(value, fallback, label) {
|
||||
const number = value === undefined ? fallback : Number(value);
|
||||
if (!Number.isInteger(number) || number < 1) {
|
||||
throw new Error(`${label} must be a positive integer`);
|
||||
}
|
||||
return number;
|
||||
}
|
||||
|
||||
function megabytesOption(value, fallbackBytes, label) {
|
||||
const megabytes = value === undefined ? fallbackBytes / 1024 / 1024 : Number(value);
|
||||
if (!Number.isFinite(megabytes) || megabytes <= 0) {
|
||||
throw new Error(`${label} must be a positive finite number`);
|
||||
}
|
||||
return Math.round(megabytes * 1024 * 1024);
|
||||
}
|
||||
|
||||
function booleanOption(value, fallback, label) {
|
||||
if (value === undefined) return fallback;
|
||||
if (typeof value === "boolean") return value;
|
||||
|
||||
Reference in New Issue
Block a user