@developerz.ai/ts23d 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/CLAUDE.md +1 -1
- package/README.md +10 -5
- package/dist/{chunk-a8fxakcj.js → chunk-6b05mnmx.js} +2 -2
- package/dist/{chunk-kgvbpqqw.js → chunk-7rtfjh9f.js} +6 -5
- package/dist/chunk-7rtfjh9f.js.map +10 -0
- package/dist/{chunk-1ypfs7ga.js → chunk-8j4c28jt.js} +790 -276
- package/dist/chunk-8j4c28jt.js.map +46 -0
- package/dist/{chunk-wtqhq529.js → chunk-d1fv6hrm.js} +6 -6
- package/dist/{chunk-wtqhq529.js.map → chunk-d1fv6hrm.js.map} +1 -1
- package/dist/{chunk-gcyp9b4d.js → chunk-dbq4qf52.js} +362 -215
- package/dist/chunk-dbq4qf52.js.map +25 -0
- package/dist/{chunk-xnt2sdhf.js → chunk-drna2rny.js} +2 -2
- package/dist/{chunk-ravbb06q.js → chunk-dxvypr7y.js} +2 -2
- package/dist/{chunk-11v28977.js → chunk-f6yme003.js} +85 -71
- package/dist/{chunk-11v28977.js.map → chunk-f6yme003.js.map} +6 -6
- package/dist/{chunk-4ddzsqtc.js → chunk-hg7pf34j.js} +4 -3
- package/dist/{chunk-4ddzsqtc.js.map → chunk-hg7pf34j.js.map} +5 -5
- package/dist/{chunk-w1zyhj40.js → chunk-jq4e17tj.js} +2 -2
- package/dist/{chunk-kvcep7ft.js → chunk-y63c6zcv.js} +967 -218
- package/dist/chunk-y63c6zcv.js.map +53 -0
- package/dist/cli/args.d.ts +7 -1
- package/dist/cli/bin.js +66 -25
- package/dist/cli/bin.js.map +6 -5
- package/dist/cli/manifest.d.ts +5 -1
- package/dist/cli/texture-cache.d.ts +4 -0
- package/dist/core/definition.d.ts +7 -0
- package/dist/core/errors.d.ts +1 -1
- package/dist/core/index.js +1 -1
- package/dist/export/credits.d.ts +4 -0
- package/dist/export/glb-options.d.ts +48 -0
- package/dist/export/glb.d.ts +5 -35
- package/dist/export/hierarchy.d.ts +23 -0
- package/dist/export/index.d.ts +2 -1
- package/dist/export/index.js +21 -7
- package/dist/export/index.js.map +1 -1
- package/dist/export/lod-coverage.d.ts +12 -0
- package/dist/export/metadata.d.ts +2 -0
- package/dist/export/version.d.ts +2 -2
- package/dist/grammar/index.js +2 -2
- package/dist/index.js +63 -17
- package/dist/index.js.map +1 -1
- package/dist/kinds/head-armour.d.ts +3 -7
- package/dist/kinds/head-bust.d.ts +3 -2
- package/dist/kinds/head-face.d.ts +3 -1
- package/dist/kinds/head-garb.d.ts +4 -0
- package/dist/kinds/head-mesh.d.ts +4 -0
- package/dist/kinds/head-mouth.d.ts +4 -0
- package/dist/kinds/head-params.d.ts +9 -1
- package/dist/kinds/head-tone.d.ts +10 -0
- package/dist/kinds/head-torso.d.ts +35 -0
- package/dist/kinds/index.js +6 -6
- package/dist/material/cc0.d.ts +4 -0
- package/dist/material/define.d.ts +34 -0
- package/dist/material/generator.d.ts +1 -1
- package/dist/material/index.d.ts +8 -3
- package/dist/material/index.js +39 -7
- package/dist/material/index.js.map +1 -1
- package/dist/material/library.d.ts +7 -0
- package/dist/material/material-def.d.ts +30 -0
- package/dist/material/paint/canvas.d.ts +7 -0
- package/dist/material/paint/default-sheet.d.ts +3 -1
- package/dist/material/paint/fabric.d.ts +4 -0
- package/dist/material/paint/image-strip.d.ts +4 -0
- package/dist/material/paint/kit.d.ts +5 -0
- package/dist/material/paint/metal.d.ts +3 -0
- package/dist/material/paint/orm.d.ts +1 -1
- package/dist/material/paint/strip.d.ts +1 -1
- package/dist/material/paint/types.d.ts +32 -2
- package/dist/material/palette.d.ts +2 -0
- package/dist/material/slots.d.ts +5 -0
- package/dist/material/texture-source.d.ts +34 -0
- package/dist/material/trim-sheet.d.ts +20 -4
- package/dist/neural/index.js +2 -2
- package/dist/passes/index.js +2 -2
- package/dist/primitives/index.js +3 -3
- package/dist/qa/index.js +2 -2
- package/dist/render/beauty.d.ts +1 -1
- package/dist/render/index.js +3 -3
- package/dist/render/lighting.d.ts +7 -0
- package/dist/render/shade.d.ts +1 -1
- package/dist/testing/index.js +5 -5
- package/docs/README.md +4 -0
- package/docs/architecture/gltf-capabilities.md +38 -1
- package/docs/architecture/materials.md +151 -0
- package/docs/idea/10-sculpting.md +166 -0
- package/docs/idea/11-materials-authoring.md +132 -0
- package/docs/idea/12-blender-bridge.md +136 -0
- package/docs/idea/13-asset-pipeline-research.md +89 -0
- package/docs/plans/roadmap.md +12 -0
- package/package.json +2 -1
- package/recipes/boxcar/README.md +7 -0
- package/recipes/boxcar/boxcar.ts +118 -34
- package/recipes/goblin_head/README.md +27 -14
- package/recipes/goblin_head/goblin_head.ts +11 -9
- package/recipes/human_head/README.md +8 -4
- package/recipes/human_head/human_head.ts +4 -3
- package/recipes/material_swatches/material_swatches.ts +11 -5
- package/recipes/orc_head/README.md +32 -20
- package/recipes/orc_head/orc_head.ts +9 -7
- package/src/cli/args.ts +16 -3
- package/src/cli/manifest.ts +6 -0
- package/src/cli/run.ts +33 -9
- package/src/cli/texture-cache.ts +24 -0
- package/src/core/asset.ts +1 -0
- package/src/core/definition.ts +7 -0
- package/src/core/errors.ts +6 -1
- package/src/export/credits.ts +25 -0
- package/src/export/glb-options.ts +53 -0
- package/src/export/glb.ts +100 -113
- package/src/export/hierarchy.ts +122 -0
- package/src/export/index.ts +17 -1
- package/src/export/lod-coverage.ts +71 -0
- package/src/export/metadata.ts +3 -0
- package/src/export/version.ts +1 -1
- package/src/kinds/head-armour.ts +103 -73
- package/src/kinds/head-bust.ts +49 -86
- package/src/kinds/head-face.ts +94 -74
- package/src/kinds/head-garb.ts +181 -0
- package/src/kinds/head-hair.ts +74 -33
- package/src/kinds/head-mesh.ts +43 -5
- package/src/kinds/head-mouth.ts +111 -0
- package/src/kinds/head-params.ts +11 -2
- package/src/kinds/head-presets.ts +30 -27
- package/src/kinds/head-tone.ts +52 -0
- package/src/kinds/head-torso.ts +230 -0
- package/src/kinds/head.ts +8 -3
- package/src/material/cc0.ts +41 -0
- package/src/material/define.ts +130 -0
- package/src/material/generator.ts +15 -8
- package/src/material/index.ts +34 -3
- package/src/material/library.ts +196 -0
- package/src/material/material-def.ts +84 -0
- package/src/material/paint/canvas.ts +11 -1
- package/src/material/paint/compose.ts +1 -1
- package/src/material/paint/decode-png.ts +19 -13
- package/src/material/paint/default-sheet.ts +40 -28
- package/src/material/paint/fabric.ts +63 -0
- package/src/material/paint/image-strip.ts +88 -0
- package/src/material/paint/kit.ts +37 -0
- package/src/material/paint/masks.ts +3 -1
- package/src/material/paint/metal.ts +109 -0
- package/src/material/paint/orm.ts +14 -1
- package/src/material/paint/planks.ts +49 -4
- package/src/material/paint/strip.ts +35 -29
- package/src/material/paint/types.ts +45 -2
- package/src/material/paint/validate.ts +19 -3
- package/src/material/palette.ts +3 -0
- package/src/material/slots.ts +18 -0
- package/src/material/texture-source.ts +86 -0
- package/src/material/trim-sheet.ts +79 -13
- package/src/render/beauty.ts +2 -2
- package/src/render/lighting.ts +26 -0
- package/src/render/shade.ts +10 -5
- package/dist/chunk-1ypfs7ga.js.map +0 -42
- package/dist/chunk-gcyp9b4d.js.map +0 -22
- package/dist/chunk-kgvbpqqw.js.map +0 -10
- package/dist/chunk-kvcep7ft.js.map +0 -43
- /package/dist/{chunk-a8fxakcj.js.map → chunk-6b05mnmx.js.map} +0 -0
- /package/dist/{chunk-xnt2sdhf.js.map → chunk-drna2rny.js.map} +0 -0
- /package/dist/{chunk-ravbb06q.js.map → chunk-dxvypr7y.js.map} +0 -0
- /package/dist/{chunk-w1zyhj40.js.map → chunk-jq4e17tj.js.map} +0 -0
package/dist/cli/args.d.ts
CHANGED
|
@@ -11,6 +11,12 @@ export interface Args {
|
|
|
11
11
|
readonly sheetSize: 512 | 1024 | 2048;
|
|
12
12
|
/** Which detail levels to build: all three by default, or e.g. only the hero mesh. */
|
|
13
13
|
readonly lods: readonly (0 | 1 | 2)[];
|
|
14
|
+
/**
|
|
15
|
+
* How LODs land on disk: `split` lodN.glb per level · `single` one <asset>.glb with MSFT_lod
|
|
16
|
+
* alternates · `both` (default): split files import everywhere, the single file is for
|
|
17
|
+
* MSFT_lod-aware loaders and one-file pipelines.
|
|
18
|
+
*/
|
|
19
|
+
readonly lodFiles: 'split' | 'single' | 'both';
|
|
14
20
|
/** Beauty-render camera and size (hero, review, and build's hero.png); unset = defaults. */
|
|
15
21
|
readonly render: {
|
|
16
22
|
readonly width?: number;
|
|
@@ -20,5 +26,5 @@ export interface Args {
|
|
|
20
26
|
readonly fovDeg?: number;
|
|
21
27
|
};
|
|
22
28
|
}
|
|
23
|
-
export declare const HELP = "usage: t3d <command> <recipe.ts\u2026> [flags]\n build GLB \u00D7 3 LODs + hero + contact sheet + manifest.json per asset; exit 1 on any QA finding\n shot contact sheet + manifest.json only (fast look)\n hero beauty render only \u2192 <out>/<asset>/hero.png (3/4 product shot, textured, shadowed)\n review AI review pack \u2192 <out>/<asset>/review/: hero, sheet, close-ups, LOD strip, review.md\n (checklist prompt for a vision agent) and review.json (image metrics + warnings)\n list the assets each module exports\nflags:\n --out <dir> output root (default: out) \u2192 <dir>/<asset>/{lod0,lod1,lod2}.glb hero.png sheet.png manifest.json\n --no-animations skip the baked 'run' clip (default: baked, so viewers can play it)\n --no-shot build without rendering hero.png and the contact sheet\n --size WxH beauty render size (default 1600x900) \u00B7 --az <deg> camera azimuth from the\n front, default -35 (front-left 3/4) \u00B7 --el <deg> elevation, default 18 \u00B7 --fov <deg> 30\n --sheet <mode> external (default): one shared trim_sheet_{albedo,normal,orm}.png in <out>/,\n referenced by every GLB \u00B7 embed: self-contained GLBs \u00B7 none: vertex colour only\n --sheet-size n 512 | 1024 (default)
|
|
29
|
+
export declare const HELP = "usage: t3d <command> <recipe.ts\u2026> [flags]\n build GLB \u00D7 3 LODs + hero + contact sheet + manifest.json per asset; exit 1 on any QA finding\n shot contact sheet + manifest.json only (fast look)\n hero beauty render only \u2192 <out>/<asset>/hero.png (3/4 product shot, textured, shadowed)\n review AI review pack \u2192 <out>/<asset>/review/: hero, sheet, close-ups, LOD strip, review.md\n (checklist prompt for a vision agent) and review.json (image metrics + warnings)\n list the assets each module exports\nflags:\n --out <dir> output root (default: out) \u2192 <dir>/<asset>/{lod0,lod1,lod2}.glb hero.png sheet.png manifest.json\n --no-animations skip the baked 'run' clip (default: baked, so viewers can play it)\n --no-shot build without rendering hero.png and the contact sheet\n --size WxH beauty render size (default 1600x900) \u00B7 --az <deg> camera azimuth from the\n front, default -35 (front-left 3/4) \u00B7 --el <deg> elevation, default 18 \u00B7 --fov <deg> 30\n --sheet <mode> external (default): one shared trim_sheet_{albedo,normal,orm}.png in <out>/,\n referenced by every GLB \u00B7 embed: self-contained GLBs \u00B7 none: vertex colour only\n --sheet-size n 512 | 1024 | 2048 (default)\n --lods <list> which detail levels to build: 0,1,2 (default) \u00B7 0 = hero only \u00B7 0,2 = near + far\n --lods <mode> how they are written: both (default) = lod0/1/2.glb + <asset>.glb \u00B7 split = lodN.glb\n only \u00B7 single = <asset>.glb only (LOD0 in the scene, LOD1/2 as MSFT_lod alternates\n with screen-coverage switch hints; viewers without MSFT_lod show LOD0 only)\n --json machine-readable output";
|
|
24
30
|
export declare function parseArgs(argv: readonly string[]): Args;
|
package/dist/cli/bin.js
CHANGED
|
@@ -3,21 +3,23 @@ import {
|
|
|
3
3
|
Ts23dError2,
|
|
4
4
|
isAsset2,
|
|
5
5
|
compile2
|
|
6
|
-
} from "../chunk-
|
|
6
|
+
} from "../chunk-hg7pf34j.js";
|
|
7
7
|
import {
|
|
8
|
+
provideTextures2,
|
|
8
9
|
DEFAULT_SHEET2,
|
|
9
10
|
paintTrimSheet2
|
|
10
|
-
} from "../chunk-
|
|
11
|
-
import"../chunk-
|
|
11
|
+
} from "../chunk-y63c6zcv.js";
|
|
12
|
+
import"../chunk-drna2rny.js";
|
|
12
13
|
import {
|
|
13
14
|
SHEET_MAPS2,
|
|
14
15
|
sheetFileName2,
|
|
15
16
|
sheetPngs2,
|
|
16
|
-
toGlb2
|
|
17
|
-
|
|
17
|
+
toGlb2,
|
|
18
|
+
exportLodGlb2
|
|
19
|
+
} from "../chunk-dbq4qf52.js";
|
|
18
20
|
import {
|
|
19
21
|
runQa2
|
|
20
|
-
} from "../chunk-
|
|
22
|
+
} from "../chunk-jq4e17tj.js";
|
|
21
23
|
import {
|
|
22
24
|
checkBeautyOptions2,
|
|
23
25
|
parseSize2,
|
|
@@ -25,14 +27,14 @@ import {
|
|
|
25
27
|
contactSheet2,
|
|
26
28
|
reviewPack2,
|
|
27
29
|
thumbnail2
|
|
28
|
-
} from "../chunk-
|
|
30
|
+
} from "../chunk-f6yme003.js";
|
|
29
31
|
import {
|
|
30
32
|
manifestOf2
|
|
31
|
-
} from "../chunk-
|
|
33
|
+
} from "../chunk-7rtfjh9f.js";
|
|
32
34
|
|
|
33
35
|
// src/cli/run.ts
|
|
34
36
|
import { mkdir as mkdir2 } from "node:fs/promises";
|
|
35
|
-
import { join as
|
|
37
|
+
import { join as join3 } from "node:path";
|
|
36
38
|
|
|
37
39
|
// src/cli/args.ts
|
|
38
40
|
var HELP = `usage: t3d <command> <recipe.ts…> [flags]
|
|
@@ -50,8 +52,11 @@ flags:
|
|
|
50
52
|
front, default -35 (front-left 3/4) · --el <deg> elevation, default 18 · --fov <deg> 30
|
|
51
53
|
--sheet <mode> external (default): one shared trim_sheet_{albedo,normal,orm}.png in <out>/,
|
|
52
54
|
referenced by every GLB · embed: self-contained GLBs · none: vertex colour only
|
|
53
|
-
--sheet-size n 512 | 1024 (default)
|
|
55
|
+
--sheet-size n 512 | 1024 | 2048 (default)
|
|
54
56
|
--lods <list> which detail levels to build: 0,1,2 (default) · 0 = hero only · 0,2 = near + far
|
|
57
|
+
--lods <mode> how they are written: both (default) = lod0/1/2.glb + <asset>.glb · split = lodN.glb
|
|
58
|
+
only · single = <asset>.glb only (LOD0 in the scene, LOD1/2 as MSFT_lod alternates
|
|
59
|
+
with screen-coverage switch hints; viewers without MSFT_lod show LOD0 only)
|
|
55
60
|
--json machine-readable output`;
|
|
56
61
|
function parseArgs(argv) {
|
|
57
62
|
const files = [];
|
|
@@ -60,8 +65,9 @@ function parseArgs(argv) {
|
|
|
60
65
|
let animations = true;
|
|
61
66
|
let shot = true;
|
|
62
67
|
let sheet = "external";
|
|
63
|
-
let sheetSize =
|
|
68
|
+
let sheetSize = 2048;
|
|
64
69
|
let lods = [0, 1, 2];
|
|
70
|
+
let lodFiles = "both";
|
|
65
71
|
const render = {};
|
|
66
72
|
const num = (flag, v) => {
|
|
67
73
|
const n = Number(v);
|
|
@@ -87,12 +93,14 @@ function parseArgs(argv) {
|
|
|
87
93
|
else if (a === "--sheet") {
|
|
88
94
|
const m = argv[++i];
|
|
89
95
|
sheet = m === "embed" || m === "none" ? m : "external";
|
|
96
|
+
} else if (a === "--lods" && /^(split|single|both)$/.test(argv[i + 1] ?? "")) {
|
|
97
|
+
lodFiles = argv[++i];
|
|
90
98
|
} else if (a === "--lods") {
|
|
91
99
|
const picked = (argv[++i] ?? "").split(",").map(Number).filter((n) => n === 0 || n === 1 || n === 2);
|
|
92
100
|
lods = picked.length ? [...new Set(picked)].sort() : lods;
|
|
93
101
|
} else if (a === "--sheet-size") {
|
|
94
102
|
const n = Number(argv[++i]);
|
|
95
|
-
sheetSize = n === 512 || n ===
|
|
103
|
+
sheetSize = n === 512 || n === 1024 ? n : 2048;
|
|
96
104
|
} else if (a === "--size")
|
|
97
105
|
Object.assign(render, parseSize2(argv[++i] ?? ""));
|
|
98
106
|
else if (a === "--az")
|
|
@@ -115,6 +123,7 @@ function parseArgs(argv) {
|
|
|
115
123
|
sheet,
|
|
116
124
|
sheetSize,
|
|
117
125
|
lods,
|
|
126
|
+
lodFiles,
|
|
118
127
|
render
|
|
119
128
|
};
|
|
120
129
|
}
|
|
@@ -175,41 +184,70 @@ function printRendered(r) {
|
|
|
175
184
|
fix: ${w.fix}`);
|
|
176
185
|
}
|
|
177
186
|
|
|
187
|
+
// src/cli/texture-cache.ts
|
|
188
|
+
import { readdir } from "node:fs/promises";
|
|
189
|
+
import { join as join2 } from "node:path";
|
|
190
|
+
var TEXTURE_CACHE = join2("node_modules", ".cache", "ts23d", "textures");
|
|
191
|
+
var sha256 = (b) => new Bun.CryptoHasher("sha256").update(b).digest("hex");
|
|
192
|
+
async function loadTextureCache(dir = TEXTURE_CACHE) {
|
|
193
|
+
const out = new Map;
|
|
194
|
+
const names = await readdir(dir).catch(() => []);
|
|
195
|
+
for (const name of names.sort()) {
|
|
196
|
+
const m = /^([0-9a-f]{64})\.png$/.exec(name);
|
|
197
|
+
if (!m?.[1])
|
|
198
|
+
continue;
|
|
199
|
+
const bytes = new Uint8Array(await Bun.file(join2(dir, name)).arrayBuffer());
|
|
200
|
+
if (sha256(bytes) === m[1])
|
|
201
|
+
out.set(m[1], bytes);
|
|
202
|
+
}
|
|
203
|
+
return out;
|
|
204
|
+
}
|
|
205
|
+
|
|
178
206
|
// src/cli/run.ts
|
|
179
207
|
async function buildOne(asset, args, texture, painted) {
|
|
180
|
-
const dir =
|
|
208
|
+
const dir = join3(args.out, asset.name);
|
|
181
209
|
await mkdir2(dir, { recursive: true });
|
|
182
210
|
const lods = args.lods.map((lod) => compile2(asset, { lod }));
|
|
183
211
|
const findings = lods.flatMap((a) => runQa2(a).map((f) => ({ ...f, message: `LOD${a.lod}: ${f.message}` })));
|
|
184
212
|
const glbs = [];
|
|
185
|
-
|
|
213
|
+
const glbOptions = { animations: args.animations, ...texture ? { sheet: texture } : {} };
|
|
214
|
+
let single;
|
|
215
|
+
let coverage = [];
|
|
216
|
+
if (args.cmd === "build" && args.lodFiles !== "single") {
|
|
186
217
|
for (const a of lods) {
|
|
187
|
-
const path =
|
|
188
|
-
await Bun.write(path, toGlb2(a,
|
|
218
|
+
const path = join3(dir, `lod${a.lod}.glb`);
|
|
219
|
+
await Bun.write(path, toGlb2(a, glbOptions));
|
|
189
220
|
glbs.push(path);
|
|
190
221
|
}
|
|
191
222
|
}
|
|
223
|
+
if (args.cmd === "build" && args.lodFiles !== "split") {
|
|
224
|
+
single = join3(dir, `${asset.name}.glb`);
|
|
225
|
+
const packed = exportLodGlb2(lods, glbOptions);
|
|
226
|
+
coverage = packed.coverage;
|
|
227
|
+
await Bun.write(single, packed.glb);
|
|
228
|
+
}
|
|
192
229
|
let sheet;
|
|
193
230
|
let thumb;
|
|
194
231
|
let hero;
|
|
195
232
|
if (args.cmd === "build" && args.shot) {
|
|
196
|
-
hero =
|
|
233
|
+
hero = join3(dir, "hero.png");
|
|
197
234
|
const top = lods[0] ?? compile2(asset);
|
|
198
235
|
await Bun.write(hero, beauty2(top, { ...args.render, ...painted ? { sheet: painted } : {} }));
|
|
199
236
|
}
|
|
200
237
|
if (args.cmd === "shot" || args.shot) {
|
|
201
|
-
thumb =
|
|
238
|
+
thumb = join3(dir, "thumb.png");
|
|
202
239
|
await Bun.write(thumb, thumbnail2(lods[0] ?? compile2(asset)));
|
|
203
|
-
sheet =
|
|
240
|
+
sheet = join3(dir, "sheet.png");
|
|
204
241
|
await Bun.write(sheet, contactSheet2(lods[0] ?? compile2(asset), { far: lods.at(-1) ?? compile2(asset, { lod: 2 }) }));
|
|
205
242
|
}
|
|
206
243
|
const manifest = manifestOf2(asset, lods, {
|
|
207
244
|
lods: glbs,
|
|
245
|
+
...single ? { single } : {},
|
|
208
246
|
...hero ? { hero } : {},
|
|
209
247
|
...sheet ? { sheet } : {},
|
|
210
248
|
...thumb ? { thumb } : {}
|
|
211
|
-
}, findings);
|
|
212
|
-
await Bun.write(
|
|
249
|
+
}, findings, coverage);
|
|
250
|
+
await Bun.write(join3(dir, "manifest.json"), `${JSON.stringify(manifest, null, 2)}
|
|
213
251
|
`);
|
|
214
252
|
return manifest;
|
|
215
253
|
}
|
|
@@ -217,6 +255,7 @@ function print(m) {
|
|
|
217
255
|
console.log(`${m.name} QA ${m.qa.pass ? "PASS" : "FAIL"} tris ${m.triangles.join("/")} draws ${m.drawCalls.join("/")}`);
|
|
218
256
|
for (const f of [
|
|
219
257
|
...m.files.lods,
|
|
258
|
+
...m.files.single ? [m.files.single] : [],
|
|
220
259
|
...m.files.hero ? [m.files.hero] : [],
|
|
221
260
|
...m.files.sheet ? [m.files.sheet] : []
|
|
222
261
|
])
|
|
@@ -248,6 +287,8 @@ async function run(argv) {
|
|
|
248
287
|
const rendered = [];
|
|
249
288
|
const renders = args.cmd === "hero" || args.cmd === "review";
|
|
250
289
|
const wantsSheet = args.cmd === "build" && args.sheet !== "none" || renders;
|
|
290
|
+
if (wantsSheet)
|
|
291
|
+
provideTextures2(await loadTextureCache());
|
|
251
292
|
const painted = wantsSheet ? paintTrimSheet2({ ...DEFAULT_SHEET2, size: args.sheetSize }) : undefined;
|
|
252
293
|
let texture;
|
|
253
294
|
if (args.cmd === "build" && args.sheet !== "none" && painted) {
|
|
@@ -257,7 +298,7 @@ async function run(argv) {
|
|
|
257
298
|
const pngs = sheetPngs2(painted);
|
|
258
299
|
await mkdir2(args.out, { recursive: true });
|
|
259
300
|
for (const map of SHEET_MAPS2)
|
|
260
|
-
await Bun.write(
|
|
301
|
+
await Bun.write(join3(args.out, sheetFileName2(map)), pngs[map]);
|
|
261
302
|
texture = { external: true, prefix: "../trim_sheet" };
|
|
262
303
|
}
|
|
263
304
|
}
|
|
@@ -289,9 +330,9 @@ async function run(argv) {
|
|
|
289
330
|
name: m.name,
|
|
290
331
|
qa: m.qa.pass ? "PASS" : "FAIL",
|
|
291
332
|
triangles: m.triangles,
|
|
292
|
-
manifest:
|
|
333
|
+
manifest: join3(m.name, "manifest.json")
|
|
293
334
|
}));
|
|
294
|
-
await Bun.write(
|
|
335
|
+
await Bun.write(join3(args.out, "index.json"), `${JSON.stringify({ ok, assets: index }, null, 2)}
|
|
295
336
|
`);
|
|
296
337
|
if (args.json)
|
|
297
338
|
console.log(JSON.stringify({ ok, data: built }));
|
|
@@ -303,5 +344,5 @@ async function run(argv) {
|
|
|
303
344
|
// src/cli/bin.ts
|
|
304
345
|
process.exitCode = await run(process.argv.slice(2));
|
|
305
346
|
|
|
306
|
-
//# debugId=
|
|
347
|
+
//# debugId=BFD08E21916B124164756E2164756E21
|
|
307
348
|
//# sourceMappingURL=bin.js.map
|
package/dist/cli/bin.js.map
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/cli/run.ts", "../src/cli/args.ts", "../src/cli/load.ts", "../src/cli/render-cmds.ts", "../src/cli/bin.ts"],
|
|
3
|
+
"sources": ["../src/cli/run.ts", "../src/cli/args.ts", "../src/cli/load.ts", "../src/cli/render-cmds.ts", "../src/cli/texture-cache.ts", "../src/cli/bin.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"// Command dispatch for `t3d`. Pure function of argv → exit code, so it is testable in-process.\n// Output layout, one folder per asset (stable paths agents and pipelines can rely on):\n// <out>/<asset>/lod0.glb lod1.glb lod2.glb hero.png thumb.png
|
|
6
|
-
"// argv → Args for `t3d`. No dependency, no magic: flags are few and documented in HELP.\n// Bad render flags (--size/--az/--el/--fov) throw T3D_RENDER_OPTIONS with the fix.\n\nimport { Ts23dError } from '../core/index.ts';\nimport { checkBeautyOptions, parseSize } from '../render/index.ts';\n\nexport interface Args {\n readonly cmd: string;\n readonly files: string[];\n readonly out: string;\n readonly json: boolean;\n readonly animations: boolean;\n /** `build` also renders the contact sheet unless --no-shot. */\n readonly shot: boolean;\n /** Trim-sheet textures: shared files in <out>/ (default), embedded per GLB, or none. */\n readonly sheet: 'external' | 'embed' | 'none';\n readonly sheetSize: 512 | 1024 | 2048;\n /** Which detail levels to build: all three by default, or e.g. only the hero mesh. */\n readonly lods: readonly (0 | 1 | 2)[];\n /** Beauty-render camera and size (hero, review, and build's hero.png); unset = defaults. */\n readonly render: {\n readonly width?: number;\n readonly height?: number;\n readonly azDeg?: number;\n readonly elDeg?: number;\n readonly fovDeg?: number;\n };\n}\n\nexport const HELP = `usage: t3d <command> <recipe.ts…> [flags]\n build GLB × 3 LODs + hero + contact sheet + manifest.json per asset; exit 1 on any QA finding\n shot contact sheet + manifest.json only (fast look)\n hero beauty render only → <out>/<asset>/hero.png (3/4 product shot, textured, shadowed)\n review AI review pack → <out>/<asset>/review/: hero, sheet, close-ups, LOD strip, review.md\n (checklist prompt for a vision agent) and review.json (image metrics + warnings)\n list the assets each module exports\nflags:\n --out <dir> output root (default: out) → <dir>/<asset>/{lod0,lod1,lod2}.glb hero.png sheet.png manifest.json\n --no-animations skip the baked 'run' clip (default: baked, so viewers can play it)\n --no-shot build without rendering hero.png and the contact sheet\n --size WxH beauty render size (default 1600x900) · --az <deg> camera azimuth from the\n front, default -35 (front-left 3/4) · --el <deg> elevation, default 18 · --fov <deg> 30\n --sheet <mode> external (default): one shared trim_sheet_{albedo,normal,orm}.png in <out>/,\n referenced by every GLB · embed: self-contained GLBs · none: vertex colour only\n --sheet-size n 512 | 1024 (default)
|
|
5
|
+
"// Command dispatch for `t3d`. Pure function of argv → exit code, so it is testable in-process.\n// Output layout, one folder per asset (stable paths agents and pipelines can rely on):\n// <out>/<asset>/lod0.glb lod1.glb lod2.glb <asset>.glb (all LODs, MSFT_lod) hero.png thumb.png\n// sheet.png manifest.json\n// <out>/<asset>/review/… (t3d review) · <out>/index.json — every asset built, with its QA verdict\n\nimport { mkdir } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { type Asset, compile, type Lod, Ts23dError } from '../core/index.ts';\nimport {\n exportLodGlb,\n SHEET_MAPS,\n type SheetBinding,\n sheetFileName,\n sheetPngs,\n toGlb,\n} from '../export/index.ts';\nimport {\n DEFAULT_SHEET,\n type PaintedSheet,\n paintTrimSheet,\n provideTextures,\n} from '../material/index.ts';\nimport { type Finding, runQa } from '../qa/index.ts';\nimport { beauty, contactSheet, thumbnail } from '../render/index.ts';\nimport { type Args, HELP, parseArgs } from './args.ts';\nimport { loadAssets } from './load.ts';\nimport { type AssetManifest, manifestOf } from './manifest.ts';\nimport { heroOne, printRendered, type RenderResult, reviewOne } from './render-cmds.ts';\nimport { loadTextureCache } from './texture-cache.ts';\n\nasync function buildOne(\n asset: Asset,\n args: Args,\n texture: SheetBinding | undefined,\n painted: PaintedSheet | undefined,\n): Promise<AssetManifest> {\n const dir = join(args.out, asset.name);\n await mkdir(dir, { recursive: true });\n // Only the LODs the user asked for: QA, GLBs and the manifest cover exactly those.\n const lods = args.lods.map((lod: Lod) => compile(asset, { lod }));\n const findings: Finding[] = lods.flatMap((a) =>\n runQa(a).map((f) => ({ ...f, message: `LOD${a.lod}: ${f.message}` })),\n );\n const glbs: string[] = [];\n const glbOptions = { animations: args.animations, ...(texture ? { sheet: texture } : {}) };\n let single: string | undefined;\n let coverage: readonly number[] = [];\n if (args.cmd === 'build' && args.lodFiles !== 'single') {\n for (const a of lods) {\n const path = join(dir, `lod${a.lod}.glb`);\n await Bun.write(path, toGlb(a, glbOptions));\n glbs.push(path);\n }\n }\n if (args.cmd === 'build' && args.lodFiles !== 'split') {\n single = join(dir, `${asset.name}.glb`);\n const packed = exportLodGlb(lods, glbOptions);\n coverage = packed.coverage;\n await Bun.write(single, packed.glb);\n }\n let sheet: string | undefined;\n let thumb: string | undefined;\n let hero: string | undefined;\n if (args.cmd === 'build' && args.shot) {\n hero = join(dir, 'hero.png');\n const top = lods[0] ?? compile(asset);\n await Bun.write(hero, beauty(top, { ...args.render, ...(painted ? { sheet: painted } : {}) }));\n }\n if (args.cmd === 'shot' || args.shot) {\n thumb = join(dir, 'thumb.png');\n await Bun.write(thumb, thumbnail(lods[0] ?? compile(asset)));\n sheet = join(dir, 'sheet.png');\n await Bun.write(\n sheet,\n contactSheet(lods[0] ?? compile(asset), { far: lods.at(-1) ?? compile(asset, { lod: 2 }) }),\n );\n }\n const manifest = manifestOf(\n asset,\n lods,\n {\n lods: glbs,\n ...(single ? { single } : {}),\n ...(hero ? { hero } : {}),\n ...(sheet ? { sheet } : {}),\n ...(thumb ? { thumb } : {}),\n },\n findings,\n coverage,\n );\n await Bun.write(join(dir, 'manifest.json'), `${JSON.stringify(manifest, null, 2)}\\n`);\n return manifest;\n}\n\nfunction print(m: AssetManifest): void {\n console.log(\n `${m.name} QA ${m.qa.pass ? 'PASS' : 'FAIL'} tris ${m.triangles.join('/')} draws ${m.drawCalls.join('/')}`,\n );\n for (const f of [\n ...m.files.lods,\n ...(m.files.single ? [m.files.single] : []),\n ...(m.files.hero ? [m.files.hero] : []),\n ...(m.files.sheet ? [m.files.sheet] : []),\n ])\n console.log(` → ${f}`);\n for (const f of m.qa.findings)\n console.log(` ✗ ${f.gate}${f.part ? ` [${f.part}]` : ''}: ${f.message}\\n fix: ${f.fix}`);\n}\n\nconst COMMANDS = ['build', 'shot', 'list', 'hero', 'review'];\n\nfunction fail(e: unknown, json: boolean): number {\n if (!(e instanceof Ts23dError)) throw e;\n console.error(\n json ? JSON.stringify({ ok: false, error: e.toJSON() }) : `${e.message}\\n fix: ${e.fix}`,\n );\n return 1;\n}\n\nexport async function run(argv: readonly string[]): Promise<number> {\n let args: Args;\n try {\n args = parseArgs(argv);\n } catch (e) {\n return fail(e, argv.includes('--json'));\n }\n if (!COMMANDS.includes(args.cmd) || args.files.length === 0) {\n console.log(HELP);\n return args.cmd === 'help' ? 0 : 2;\n }\n const built: AssetManifest[] = [];\n const rendered: RenderResult[] = [];\n // Paint the trim sheet once per run (~4 s at 2048²). External mode writes it once into <out>/\n // and every GLB in <out>/<asset>/ references ../trim_sheet_*.png — one texture set for all.\n // The beauty renders sample the same painted sheet.\n const renders = args.cmd === 'hero' || args.cmd === 'review';\n const wantsSheet = (args.cmd === 'build' && args.sheet !== 'none') || renders;\n if (wantsSheet) provideTextures(await loadTextureCache());\n const painted = wantsSheet\n ? paintTrimSheet({ ...DEFAULT_SHEET, size: args.sheetSize })\n : undefined;\n let texture: SheetBinding | undefined;\n if (args.cmd === 'build' && args.sheet !== 'none' && painted) {\n if (args.sheet === 'embed') texture = painted;\n else {\n const pngs = sheetPngs(painted);\n await mkdir(args.out, { recursive: true });\n for (const map of SHEET_MAPS) await Bun.write(join(args.out, sheetFileName(map)), pngs[map]);\n texture = { external: true, prefix: '../trim_sheet' };\n }\n }\n try {\n for (const file of args.files) {\n for (const asset of await loadAssets(file)) {\n if (args.cmd === 'list')\n console.log(\n args.json ? JSON.stringify({ asset: asset.name, file }) : `${asset.name} ${file}`,\n );\n else if (renders && painted)\n rendered.push(\n args.cmd === 'hero'\n ? await heroOne(asset, args, painted)\n : await reviewOne(asset, file, args, painted),\n );\n else built.push(await buildOne(asset, args, texture, painted));\n }\n }\n } catch (e) {\n return fail(e, args.json);\n }\n if (args.cmd === 'list') return 0;\n if (renders) {\n if (args.json) console.log(JSON.stringify({ ok: true, data: rendered }));\n else rendered.forEach(printRendered);\n return 0;\n }\n const ok = built.every((m) => m.qa.pass);\n const index = built.map((m) => ({\n name: m.name,\n qa: m.qa.pass ? 'PASS' : 'FAIL',\n triangles: m.triangles,\n manifest: join(m.name, 'manifest.json'),\n }));\n await Bun.write(\n join(args.out, 'index.json'),\n `${JSON.stringify({ ok, assets: index }, null, 2)}\\n`,\n );\n if (args.json) console.log(JSON.stringify({ ok, data: built }));\n else built.forEach(print);\n return ok ? 0 : 1;\n}\n",
|
|
6
|
+
"// argv → Args for `t3d`. No dependency, no magic: flags are few and documented in HELP.\n// Bad render flags (--size/--az/--el/--fov) throw T3D_RENDER_OPTIONS with the fix.\n\nimport { Ts23dError } from '../core/index.ts';\nimport { checkBeautyOptions, parseSize } from '../render/index.ts';\n\nexport interface Args {\n readonly cmd: string;\n readonly files: string[];\n readonly out: string;\n readonly json: boolean;\n readonly animations: boolean;\n /** `build` also renders the contact sheet unless --no-shot. */\n readonly shot: boolean;\n /** Trim-sheet textures: shared files in <out>/ (default), embedded per GLB, or none. */\n readonly sheet: 'external' | 'embed' | 'none';\n readonly sheetSize: 512 | 1024 | 2048;\n /** Which detail levels to build: all three by default, or e.g. only the hero mesh. */\n readonly lods: readonly (0 | 1 | 2)[];\n /**\n * How LODs land on disk: `split` lodN.glb per level · `single` one <asset>.glb with MSFT_lod\n * alternates · `both` (default): split files import everywhere, the single file is for\n * MSFT_lod-aware loaders and one-file pipelines.\n */\n readonly lodFiles: 'split' | 'single' | 'both';\n /** Beauty-render camera and size (hero, review, and build's hero.png); unset = defaults. */\n readonly render: {\n readonly width?: number;\n readonly height?: number;\n readonly azDeg?: number;\n readonly elDeg?: number;\n readonly fovDeg?: number;\n };\n}\n\nexport const HELP = `usage: t3d <command> <recipe.ts…> [flags]\n build GLB × 3 LODs + hero + contact sheet + manifest.json per asset; exit 1 on any QA finding\n shot contact sheet + manifest.json only (fast look)\n hero beauty render only → <out>/<asset>/hero.png (3/4 product shot, textured, shadowed)\n review AI review pack → <out>/<asset>/review/: hero, sheet, close-ups, LOD strip, review.md\n (checklist prompt for a vision agent) and review.json (image metrics + warnings)\n list the assets each module exports\nflags:\n --out <dir> output root (default: out) → <dir>/<asset>/{lod0,lod1,lod2}.glb hero.png sheet.png manifest.json\n --no-animations skip the baked 'run' clip (default: baked, so viewers can play it)\n --no-shot build without rendering hero.png and the contact sheet\n --size WxH beauty render size (default 1600x900) · --az <deg> camera azimuth from the\n front, default -35 (front-left 3/4) · --el <deg> elevation, default 18 · --fov <deg> 30\n --sheet <mode> external (default): one shared trim_sheet_{albedo,normal,orm}.png in <out>/,\n referenced by every GLB · embed: self-contained GLBs · none: vertex colour only\n --sheet-size n 512 | 1024 | 2048 (default)\n --lods <list> which detail levels to build: 0,1,2 (default) · 0 = hero only · 0,2 = near + far\n --lods <mode> how they are written: both (default) = lod0/1/2.glb + <asset>.glb · split = lodN.glb\n only · single = <asset>.glb only (LOD0 in the scene, LOD1/2 as MSFT_lod alternates\n with screen-coverage switch hints; viewers without MSFT_lod show LOD0 only)\n --json machine-readable output`;\n\nexport function parseArgs(argv: readonly string[]): Args {\n const files: string[] = [];\n let out = 'out';\n let json = false;\n let animations = true;\n let shot = true;\n let sheet: Args['sheet'] = 'external';\n let sheetSize: Args['sheetSize'] = 2048;\n let lods: Args['lods'] = [0, 1, 2];\n let lodFiles: Args['lodFiles'] = 'both';\n const render: {\n width?: number;\n height?: number;\n azDeg?: number;\n elDeg?: number;\n fovDeg?: number;\n } = {};\n const num = (flag: string, v: string | undefined): number => {\n const n = Number(v);\n if (v === undefined || v.trim() === '' || !Number.isFinite(n))\n throw new Ts23dError('T3D_RENDER_OPTIONS', {\n cause: `${flag} needs a number of degrees, got ${v === undefined ? 'nothing' : `\"${v}\"`}`,\n fix: `pass e.g. ${flag} ${flag === '--fov' ? 30 : flag === '--el' ? 18 : -35}`,\n });\n return n;\n };\n for (let i = 1; i < argv.length; i++) {\n const a = argv[i] ?? '';\n if (a === '--json') json = true;\n else if (a === '--no-animations') animations = false;\n else if (a === '--animations') animations = true;\n else if (a === '--no-shot') shot = false;\n else if (a === '--out') out = argv[++i] ?? out;\n else if (a === '--sheet') {\n const m = argv[++i];\n sheet = m === 'embed' || m === 'none' ? m : 'external';\n } else if (a === '--lods' && /^(split|single|both)$/.test(argv[i + 1] ?? '')) {\n lodFiles = argv[++i] as Args['lodFiles'];\n } else if (a === '--lods') {\n const picked = (argv[++i] ?? '')\n .split(',')\n .map(Number)\n .filter((n): n is 0 | 1 | 2 => n === 0 || n === 1 || n === 2);\n lods = picked.length ? [...new Set(picked)].sort() : lods;\n } else if (a === '--sheet-size') {\n const n = Number(argv[++i]);\n sheetSize = n === 512 || n === 1024 ? n : 2048;\n } else if (a === '--size') Object.assign(render, parseSize(argv[++i] ?? ''));\n else if (a === '--az') render.azDeg = num(a, argv[++i]);\n else if (a === '--el') render.elDeg = num(a, argv[++i]);\n else if (a === '--fov') render.fovDeg = num(a, argv[++i]);\n else files.push(a);\n }\n checkBeautyOptions(render);\n return {\n cmd: argv[0] ?? 'help',\n files,\n out,\n json,\n animations,\n shot,\n sheet,\n sheetSize,\n lods,\n lodFiles,\n render,\n };\n}\n",
|
|
7
7
|
"// Load a recipe module and collect every exported Asset. Recipes are plain TS modules: the CLI,\n// the site and tests all import them the same way.\n\nimport { resolve } from 'node:path';\nimport { type Asset, isAsset, Ts23dError } from '../core/index.ts';\n\nexport async function loadAssets(file: string): Promise<Asset[]> {\n const mod: Record<string, unknown> = await import(resolve(file));\n const assets = Object.values(mod).filter(isAsset);\n if (assets.length === 0) {\n throw new Ts23dError('T3D_NO_ASSET_EXPORT', {\n cause: `${file} exports no asset`,\n fix: 'export const my_thing = defineAsset({ … }) — named export, no default',\n });\n }\n return assets;\n}\n",
|
|
8
8
|
"// `t3d hero` and `t3d review`: beauty renders and the AI review pack, one folder per asset.\n// <out>/<asset>/hero.png\n// <out>/<asset>/review/{hero,sheet,detail_1,detail_2,lods}.png review.md review.json\n\nimport { mkdir } from 'node:fs/promises';\nimport { dirname, join, relative, resolve } from 'node:path';\nimport { type Asset, compile } from '../core/index.ts';\nimport type { PaintedSheet } from '../material/index.ts';\nimport { beauty, type ReviewWarning, reviewPack } from '../render/index.ts';\nimport type { Args } from './args.ts';\n\nexport interface RenderResult {\n readonly name: string;\n readonly files: readonly string[];\n readonly warnings: readonly ReviewWarning[];\n}\n\nexport async function heroOne(\n asset: Asset,\n args: Args,\n sheet: PaintedSheet,\n): Promise<RenderResult> {\n const dir = join(args.out, asset.name);\n await mkdir(dir, { recursive: true });\n const path = join(dir, 'hero.png');\n await Bun.write(path, beauty(compile(asset, { lod: 0 }), { ...args.render, sheet }));\n return { name: asset.name, files: [path], warnings: [] };\n}\n\n/** The dossier: README.md next to the recipe (recipes/<name>/), else a legacy refs/<name>.md. */\nasync function refsFor(name: string, recipe: string): Promise<string | undefined> {\n for (const p of [\n join(dirname(resolve(recipe)), 'README.md'),\n join(dirname(resolve(recipe)), '..', 'refs', `${name}.md`),\n resolve('refs', `${name}.md`),\n ])\n if (await Bun.file(p).exists()) return relative(process.cwd(), p) || p;\n return undefined;\n}\n\nexport async function reviewOne(\n asset: Asset,\n recipe: string,\n args: Args,\n sheet: PaintedSheet,\n): Promise<RenderResult> {\n const dir = join(args.out, asset.name, 'review');\n await mkdir(dir, { recursive: true });\n const refs = await refsFor(asset.name, recipe);\n const pack = reviewPack(asset, { ...args.render, sheet, ...(refs ? { refs } : {}) });\n const files: string[] = [];\n for (const [name, bytes] of pack.files) {\n const path = join(dir, name);\n await Bun.write(path, bytes);\n files.push(path);\n }\n return { name: asset.name, files, warnings: pack.metrics.warnings };\n}\n\nexport function printRendered(r: RenderResult): void {\n console.log(\n `${r.name} ${r.warnings.length ? `${r.warnings.length} warning(s)` : 'no warnings'}`,\n );\n for (const f of r.files) console.log(` → ${f}`);\n for (const w of r.warnings) console.log(` ! ${w.code}: ${w.message}\\n fix: ${w.fix}`);\n}\n",
|
|
9
|
+
"// The local CC0 texture cache (`bun run textures` fills it): every file re-verified by its sha256\n// name, handed to `provideTextures` before painting. Missing files are fine here; painting a\n// material that needs one throws T3D_TEXTURE_MISSING with the fetch command.\n\nimport { readdir } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { TextureCache } from '../material/index.ts';\n\nexport const TEXTURE_CACHE = join('node_modules', '.cache', 'ts23d', 'textures');\n\nconst sha256 = (b: Uint8Array): string => new Bun.CryptoHasher('sha256').update(b).digest('hex');\n\n/** Every cached map whose bytes still match its sha256 name. */\nexport async function loadTextureCache(dir = TEXTURE_CACHE): Promise<TextureCache> {\n const out = new Map<string, Uint8Array>();\n const names = await readdir(dir).catch(() => [] as string[]);\n for (const name of names.sort()) {\n const m = /^([0-9a-f]{64})\\.png$/.exec(name);\n if (!m?.[1]) continue;\n const bytes = new Uint8Array(await Bun.file(join(dir, name)).arrayBuffer());\n if (sha256(bytes) === m[1]) out.set(m[1], bytes);\n }\n return out;\n}\n",
|
|
9
10
|
"#!/usr/bin/env bun\n// `t3d` — compile TypeScript recipes to GLB, gate them, and shoot contact sheets. `t3d help`\n// prints the commands; src/cli/args.ts holds the flags, src/cli/run.ts the output layout.\n\nimport { run } from './run.ts';\n\nprocess.exitCode = await run(process.argv.slice(2));\n"
|
|
10
11
|
],
|
|
11
|
-
"mappings": "
|
|
12
|
-
"debugId": "
|
|
12
|
+
"mappings": "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",
|
|
13
|
+
"debugId": "BFD08E21916B124164756E2164756E21",
|
|
13
14
|
"names": []
|
|
14
15
|
}
|
package/dist/cli/manifest.d.ts
CHANGED
|
@@ -7,11 +7,15 @@ export interface AssetManifest {
|
|
|
7
7
|
readonly tags: readonly string[];
|
|
8
8
|
readonly files: {
|
|
9
9
|
readonly lods: readonly string[];
|
|
10
|
+
/** All built LODs in one GLB (MSFT_lod), when `--lods single|both`. */
|
|
11
|
+
readonly single?: string;
|
|
10
12
|
readonly hero?: string;
|
|
11
13
|
readonly sheet?: string;
|
|
12
14
|
readonly thumb?: string;
|
|
13
15
|
};
|
|
14
16
|
readonly triangles: readonly number[];
|
|
17
|
+
/** MSFT_screencoverage written into `files.single`: where each LOD hands over (last = cull). */
|
|
18
|
+
readonly lodCoverage?: readonly number[];
|
|
15
19
|
readonly drawCalls: readonly number[];
|
|
16
20
|
readonly pivots: readonly {
|
|
17
21
|
name: string;
|
|
@@ -46,4 +50,4 @@ export interface AssetManifest {
|
|
|
46
50
|
readonly findings: readonly Finding[];
|
|
47
51
|
};
|
|
48
52
|
}
|
|
49
|
-
export declare function manifestOf(asset: Asset, lods: readonly CompiledAsset[], files: AssetManifest['files'], findings: readonly Finding[]): AssetManifest;
|
|
53
|
+
export declare function manifestOf(asset: Asset, lods: readonly CompiledAsset[], files: AssetManifest['files'], findings: readonly Finding[], lodCoverage?: readonly number[]): AssetManifest;
|
|
@@ -129,6 +129,12 @@ export interface AssetDefinition {
|
|
|
129
129
|
readonly creators?: readonly string[];
|
|
130
130
|
/** Emissive part sets; `t3d build` writes them as glowing materials. */
|
|
131
131
|
readonly glow?: readonly Glow[];
|
|
132
|
+
/**
|
|
133
|
+
* View-distance hints for the single-file GLB (MSFT_lod `MSFT_screencoverage`): the screen-height
|
|
134
|
+
* fraction below which LOD0 → LOD1, LOD1 → LOD2, and LOD2 is culled (0 = never). Strictly
|
|
135
|
+
* descending, 1 > a > b > c >= 0. Omitted: derived from the triangle counts and size.
|
|
136
|
+
*/
|
|
137
|
+
readonly lodCoverage?: readonly [number, number, number];
|
|
132
138
|
build(ctx: BuildContext): void;
|
|
133
139
|
}
|
|
134
140
|
export interface Asset extends AssetDefinition {
|
|
@@ -145,4 +151,5 @@ export interface CompiledAsset {
|
|
|
145
151
|
/** Provenance carried from the definition (absent when the recipe declares none). */
|
|
146
152
|
readonly meta?: AssetMeta;
|
|
147
153
|
readonly glow?: readonly Glow[];
|
|
154
|
+
readonly lodCoverage?: readonly [number, number, number];
|
|
148
155
|
}
|
package/dist/core/errors.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type ErrorCode = 'T3D_NOT_IMPLEMENTED' | 'T3D_GRAMMAR_SYNTAX' | 'T3D_GRAMMAR_OVERFLOW' | 'T3D_PART_DUPLICATE' | 'T3D_PART_UNKNOWN' | 'T3D_RECIPE_INVALID' | 'T3D_NO_ASSET_EXPORT' | 'T3D_QA_FAILED' | 'T3D_RENDER_OPTIONS' | 'T3D_AMBIENT_RANDOM' | 'T3D_RELEASE' | 'T3D_BENCH';
|
|
1
|
+
export type ErrorCode = 'T3D_NOT_IMPLEMENTED' | 'T3D_GRAMMAR_SYNTAX' | 'T3D_GRAMMAR_OVERFLOW' | 'T3D_PART_DUPLICATE' | 'T3D_PART_UNKNOWN' | 'T3D_RECIPE_INVALID' | 'T3D_NO_ASSET_EXPORT' | 'T3D_QA_FAILED' | 'T3D_RENDER_OPTIONS' | 'T3D_AMBIENT_RANDOM' | 'T3D_RELEASE' | 'T3D_BENCH' | 'T3D_MATERIAL_INVALID' | 'T3D_MATERIAL_UNKNOWN' | 'T3D_MATERIAL_CONFLICT' | 'T3D_SHEET_FULL' | 'T3D_TEXTURE_MISSING';
|
|
2
2
|
export interface ErrorDetails {
|
|
3
3
|
readonly cause: string;
|
|
4
4
|
readonly fix: string;
|
package/dist/core/index.js
CHANGED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { CompiledAsset } from '../core/index.js';
|
|
2
|
+
import type { GlbMeta } from './metadata.js';
|
|
3
|
+
export declare function creditsOf(asset: CompiledAsset): string[];
|
|
4
|
+
export declare function withCredits(asset: CompiledAsset, meta: GlbMeta | undefined): GlbMeta | undefined;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { OptimizeOptions } from '../passes/index.js';
|
|
2
|
+
import type { LodCoverage } from './lod-coverage.js';
|
|
3
|
+
import type { GlowRule } from './materials.js';
|
|
4
|
+
import type { GlbMeta } from './metadata.js';
|
|
5
|
+
import type { ExportReport } from './optimize-parts.js';
|
|
6
|
+
import type { SheetBinding } from './textures.js';
|
|
7
|
+
export interface GlbOptions {
|
|
8
|
+
/** Keep every part as its own node (debugging, per-part picking). Default merges to pivots. */
|
|
9
|
+
readonly keepParts?: boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Bake each part's `motion` into a looping `run` clip. Off by default: glTF has no autoplay
|
|
12
|
+
* flag and most viewers play the first clip, while engines usually drive the named pivots
|
|
13
|
+
* from game code. Turn it on for previews, cutscenes and ambient props.
|
|
14
|
+
*/
|
|
15
|
+
readonly animations?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Bind the painted trim sheet to every material: a `PaintedSheet` embeds the three PNGs (one
|
|
18
|
+
* self-contained file); `{ external: true, prefix? }` references shared `trim_sheet_*.png` by
|
|
19
|
+
* URI. Omitted: no textures, byte-identical to the untextured output.
|
|
20
|
+
*/
|
|
21
|
+
readonly sheet?: SheetBinding;
|
|
22
|
+
/**
|
|
23
|
+
* Weld + vertex-cache + vertex-fetch optimisation per primitive (passes/optimize). On by
|
|
24
|
+
* default; `false` writes the meshes exactly as compiled (debugging the IR).
|
|
25
|
+
*/
|
|
26
|
+
readonly optimize?: boolean | OptimizeOptions;
|
|
27
|
+
/** Parts that emit light (lamp lenses, lit windows): one emissive material per rule. */
|
|
28
|
+
readonly glow?: readonly GlowRule[];
|
|
29
|
+
/** Provenance: asset.copyright + an XMP packet (title, creators, licence, sources). */
|
|
30
|
+
readonly meta?: GlbMeta;
|
|
31
|
+
/**
|
|
32
|
+
* Single-file LODs only: [LOD0→LOD1, LOD1→LOD2, cull] screen-height fractions written as
|
|
33
|
+
* `MSFT_screencoverage`. Default: the asset's `lodCoverage`, else derived (lod-coverage.ts).
|
|
34
|
+
*/
|
|
35
|
+
readonly lodCoverage?: LodCoverage;
|
|
36
|
+
}
|
|
37
|
+
/** The GLB bytes plus what the optimiser did (vertex counts, ACMR before/after, per part). */
|
|
38
|
+
export interface GlbResult {
|
|
39
|
+
readonly glb: Uint8Array;
|
|
40
|
+
readonly report: ExportReport;
|
|
41
|
+
}
|
|
42
|
+
/** One GLB holding several LODs, plus one optimiser report per LOD (same order as the input). */
|
|
43
|
+
export interface LodGlbResult {
|
|
44
|
+
readonly glb: Uint8Array;
|
|
45
|
+
readonly reports: readonly ExportReport[];
|
|
46
|
+
/** The `MSFT_screencoverage` written (empty for a single LOD). */
|
|
47
|
+
readonly coverage: readonly number[];
|
|
48
|
+
}
|
package/dist/export/glb.d.ts
CHANGED
|
@@ -1,38 +1,8 @@
|
|
|
1
1
|
import type { CompiledAsset } from '../core/index.js';
|
|
2
|
-
import type {
|
|
3
|
-
|
|
4
|
-
import { type GlbMeta } from './metadata.js';
|
|
5
|
-
import { type ExportReport } from './optimize-parts.js';
|
|
6
|
-
import { type SheetBinding } from './textures.js';
|
|
7
|
-
export interface GlbOptions {
|
|
8
|
-
/** Keep every part as its own node (debugging, per-part picking). Default merges to pivots. */
|
|
9
|
-
readonly keepParts?: boolean;
|
|
10
|
-
/**
|
|
11
|
-
* Bake each part's `motion` into a looping `run` clip. Off by default: glTF has no autoplay
|
|
12
|
-
* flag and most viewers play the first clip, while engines usually drive the named pivots
|
|
13
|
-
* from game code. Turn it on for previews, cutscenes and ambient props.
|
|
14
|
-
*/
|
|
15
|
-
readonly animations?: boolean;
|
|
16
|
-
/**
|
|
17
|
-
* Bind the painted trim sheet to every material: a `PaintedSheet` embeds the three PNGs (one
|
|
18
|
-
* self-contained file); `{ external: true, prefix? }` references shared `trim_sheet_*.png` by
|
|
19
|
-
* URI. Omitted: no textures, byte-identical to the untextured output.
|
|
20
|
-
*/
|
|
21
|
-
readonly sheet?: SheetBinding;
|
|
22
|
-
/**
|
|
23
|
-
* Weld + vertex-cache + vertex-fetch optimisation per primitive (passes/optimize). On by
|
|
24
|
-
* default; `false` writes the meshes exactly as compiled (debugging the IR).
|
|
25
|
-
*/
|
|
26
|
-
readonly optimize?: boolean | OptimizeOptions;
|
|
27
|
-
/** Parts that emit light (lamp lenses, lit windows): one emissive material per rule. */
|
|
28
|
-
readonly glow?: readonly GlowRule[];
|
|
29
|
-
/** Provenance: asset.copyright + an XMP packet (title, creators, licence, sources). */
|
|
30
|
-
readonly meta?: GlbMeta;
|
|
31
|
-
}
|
|
32
|
-
/** The GLB bytes plus what the optimiser did (vertex counts, ACMR before/after, per part). */
|
|
33
|
-
export interface GlbResult {
|
|
34
|
-
readonly glb: Uint8Array;
|
|
35
|
-
readonly report: ExportReport;
|
|
36
|
-
}
|
|
2
|
+
import type { GlbOptions, GlbResult, LodGlbResult } from './glb-options.js';
|
|
3
|
+
export type { GlbOptions, GlbResult, LodGlbResult } from './glb-options.js';
|
|
37
4
|
export declare function toGlb(input: CompiledAsset, o?: GlbOptions): Uint8Array;
|
|
38
5
|
export declare function exportGlb(input: CompiledAsset, o?: GlbOptions): GlbResult;
|
|
6
|
+
/** All LODs in one GLB: LOD0 in the scene, the rest as MSFT_lod alternates outside it. */
|
|
7
|
+
export declare function toLodGlb(lods: readonly CompiledAsset[], o?: GlbOptions): Uint8Array;
|
|
8
|
+
export declare function exportLodGlb(lods: readonly CompiledAsset[], o?: GlbOptions): LodGlbResult;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { CompiledAsset, Part } from '../core/index.js';
|
|
2
|
+
import type { BinWriter, Json } from './bin-writer.js';
|
|
3
|
+
/** The growing glTF arrays every LOD appends to. */
|
|
4
|
+
export interface GltfDoc {
|
|
5
|
+
readonly bin: BinWriter;
|
|
6
|
+
readonly nodes: Json[];
|
|
7
|
+
readonly meshes: Json[];
|
|
8
|
+
readonly lights: Json[];
|
|
9
|
+
readonly samplers: Json[];
|
|
10
|
+
readonly channels: Json[];
|
|
11
|
+
/** motion + rest pose → sampler index: the same wheel spin at LOD0 and LOD1 is one sampler. */
|
|
12
|
+
readonly motionSamplers: Map<string, number>;
|
|
13
|
+
readonly lightIndex: Map<string, number>;
|
|
14
|
+
}
|
|
15
|
+
export declare const newDoc: (bin: BinWriter) => GltfDoc;
|
|
16
|
+
export interface HierarchyOptions {
|
|
17
|
+
/** Material index for a part (trim sheet by surface, or its glow layer). */
|
|
18
|
+
readonly materialOf: (part: Part, i: number) => number;
|
|
19
|
+
readonly withSheet: boolean;
|
|
20
|
+
readonly animations: boolean;
|
|
21
|
+
}
|
|
22
|
+
/** Appends `asset`'s tree under a new root named `rootName`; returns the root node index. */
|
|
23
|
+
export declare function writeHierarchy(doc: GltfDoc, asset: CompiledAsset, rootName: string, o: HierarchyOptions): number;
|
package/dist/export/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
export { exportGlb, type GlbOptions, type GlbResult, toGlb } from './glb.js';
|
|
1
|
+
export { exportGlb, exportLodGlb, type GlbOptions, type GlbResult, type LodGlbResult, toGlb, toLodGlb, } from './glb.js';
|
|
2
|
+
export { checkCoverage, coverageFor, defaultCoverage, type LodCoverage, MSFT_LOD, SCREEN_COVERAGE, } from './lod-coverage.js';
|
|
2
3
|
export { mergeToPivots } from './merge-pivots.js';
|
|
3
4
|
export { type ExportReport, optimizeParts, type PartOptimizeReport, summarize, } from './optimize-parts.js';
|
|
4
5
|
export { type ExternalSheet, SHEET_MAPS, type SheetBinding, type SheetMap, sheetFileName, sheetPngs, } from './textures.js';
|
package/dist/export/index.js
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
|
+
MSFT_LOD2,
|
|
3
|
+
SCREEN_COVERAGE2,
|
|
4
|
+
defaultCoverage2,
|
|
5
|
+
checkCoverage2,
|
|
6
|
+
coverageFor2,
|
|
2
7
|
mergeToPivots2,
|
|
3
8
|
summarize2,
|
|
4
9
|
optimizeParts2,
|
|
@@ -6,21 +11,30 @@ import {
|
|
|
6
11
|
sheetFileName2,
|
|
7
12
|
sheetPngs2,
|
|
8
13
|
toGlb2,
|
|
9
|
-
exportGlb2
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
import"../chunk-
|
|
14
|
+
exportGlb2,
|
|
15
|
+
toLodGlb2,
|
|
16
|
+
exportLodGlb2
|
|
17
|
+
} from "../chunk-dbq4qf52.js";
|
|
18
|
+
import"../chunk-y63c6zcv.js";
|
|
19
|
+
import"../chunk-drna2rny.js";
|
|
20
|
+
import"../chunk-hg7pf34j.js";
|
|
14
21
|
export {
|
|
22
|
+
MSFT_LOD2 as MSFT_LOD,
|
|
23
|
+
SCREEN_COVERAGE2 as SCREEN_COVERAGE,
|
|
15
24
|
SHEET_MAPS2 as SHEET_MAPS,
|
|
25
|
+
checkCoverage2 as checkCoverage,
|
|
26
|
+
coverageFor2 as coverageFor,
|
|
27
|
+
defaultCoverage2 as defaultCoverage,
|
|
16
28
|
exportGlb2 as exportGlb,
|
|
29
|
+
exportLodGlb2 as exportLodGlb,
|
|
17
30
|
mergeToPivots2 as mergeToPivots,
|
|
18
31
|
optimizeParts2 as optimizeParts,
|
|
19
32
|
sheetFileName2 as sheetFileName,
|
|
20
33
|
sheetPngs2 as sheetPngs,
|
|
21
34
|
summarize2 as summarize,
|
|
22
|
-
toGlb2 as toGlb
|
|
35
|
+
toGlb2 as toGlb,
|
|
36
|
+
toLodGlb2 as toLodGlb
|
|
23
37
|
};
|
|
24
38
|
|
|
25
|
-
//# debugId=
|
|
39
|
+
//# debugId=8BD3B1362543914364756E2164756E21
|
|
26
40
|
//# sourceMappingURL=index.js.map
|