clone

an endless marble-race generator in the browser; the url is the seed, so every track can be shared

main
marbles / tools / import_assets.ts
import_assets.ts 3.0K
1#!/usr/bin/env -S deno run --allow-read --allow-write --allow-env2/**3 * Asset import pipeline.4 *5 * Merges each Kenney pack's per-piece GLBs into one GLB plus a `PackManifest`6 * that the generator and renderer consume.7 *8 * deno task assets:import9 * deno task assets:import -- --pack "Marble Kit" --out assets/10 */11import { parseArgs } from "@std/cli";12import { importPack, type PackResult } from "./lib/pack.ts";1314const DEFAULT_SOURCE_ROOT =15 "/Users/dami/Documents/Game Dev Asset Packs/kennygames/3D assets";16const DEFAULT_PACKS = [17 "Marble Kit",18 "Nature Kit",19 // M18a theme packs: winter / spooky / tropical / autumn biome rows.20 "Holiday Kit",21 "Graveyard Kit",22 "Pirate Kit",23 "Survival Kit",24 // M18b void decor: meteors, craft, satellites drift in the void.25 "Space Kit",26 // Island mass families round: block voxel families.27 "Platformer Kit",28];29const DEFAULT_OUT = "assets/";3031function formatBytes(n: number): string {32 if (n < 1024) return `${n} B`;33 if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`;34 return `${(n / (1024 * 1024)).toFixed(2)} MB`;35}3637function printSummary(results: PackResult[]): void {38 const header = [39 "pack",40 "pieces",41 "input",42 "output",43 "tex before",44 "tex after",45 ];46 const rows = results.map((r) => [47 r.manifest.pack,48 String(r.manifest.pieceCount),49 formatBytes(r.inputBytes),50 formatBytes(r.outputBytes),51 String(r.texturesBefore),52 String(r.texturesAfter),53 ]);54 const widths = header.map((h, i) =>55 Math.max(h.length, ...rows.map((row) => row[i].length))56 );57 const line = (cells: string[]) =>58 cells.map((c, i) => i === 0 ? c.padEnd(widths[i]) : c.padStart(widths[i]))59 .join(" ");6061 console.log("");62 console.log(line(header));63 console.log(widths.map((w) => "-".repeat(w)).join(" "));64 for (const row of rows) console.log(line(row));65 console.log("");66}6768async function main(): Promise<number> {69 const flags = parseArgs(Deno.args, {70 string: ["source-root", "pack", "out"],71 collect: ["pack"],72 default: { "source-root": DEFAULT_SOURCE_ROOT, out: DEFAULT_OUT },73 });7475 const sourceRoot = flags["source-root"];76 const out = flags.out;77 const packs = flags.pack.length > 0 ? flags.pack : DEFAULT_PACKS;7879 const results: PackResult[] = [];80 const failures: string[] = [];8182 for (const pack of packs) {83 console.log(`importing ${pack} …`);84 try {85 const result = await importPack(sourceRoot, pack, out);86 console.log(87 ` ${result.manifest.pieceCount} pieces -> ${result.manifest.glbPath}`,88 );89 results.push(result);90 } catch (error) {91 const message = error instanceof Error ? error.message : String(error);92 console.error(` FAILED: ${message}`);93 failures.push(pack);94 }95 }9697 if (results.length > 0) printSummary(results);9899 if (failures.length > 0) {100 console.error(`import failed for: ${failures.join(", ")}`);101 return 1;102 }103 return 0;104}105106if (import.meta.main) {107 Deno.exit(await main());108}