feat(world): Palmen und Requisiten als Instanzen mit Stammkollision

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
knsoandClaude Sonnet 5 committed 2026-09-13 01:05:55 +02:00
1 parent 2469d30e76
commit 9173400caa
16 files changed
+2504 -1

No files matched your search

+10
View File
@@ -0,0 +1,10 @@
#!/usr/bin/env bash
# Nobiax-Palme (CC0) holen und die TGA-Texturen nach PNG wandeln.
set -e
mkdir -p public/models/palm && cd public/models/palm
curl -sL -o palm.7z "https://opengameart.org/sites/default/files/palm_tree_v2.7z"
tar -xf palm.7z
sips -s format png diffus.tga --out diffuse.png > /dev/null
sips -s format png normal.tga --out normal.png > /dev/null
rm -f palm.7z diffus.tga normal.tga specular.tga palm_tree.FBX preview.jpg
echo "Palme bereit: $(ls)"
+41
View File
@@ -0,0 +1,41 @@
// Lädt die fünf Poly-Haven-Requisiten in 1k (gltf + zugehörige Texturen/`.bin`) nach
// public/models/props/raw/ und vereinfacht sie danach mit @gltf-transform/cli zu je einer
// kompakten .glb unter public/models/props/. Gleiches Muster wie textures.mjs, aber Modelle
// stehen unter dem Schlüssel "gltf" statt unter den Map-Namen ("Diffuse", "nor_gl", "arm"),
// und die 1k-Auflösung liefert neben der .gltf-Datei selbst noch eine `include`-Liste mit den
// referenzierten Texturen und der gemeinsamen `.bin`-Geometriedatei — ohne die kann
// gltf-transform die .gltf-Datei nicht öffnen.
import { execFileSync } from "node:child_process";
import { mkdir, writeFile } from "node:fs/promises";
import { dirname, join } from "node:path";
const UA = { "User-Agent": "leonida-assets/0.1 (local hobby project)" };
const SLUGS = ["street_lamp_02", "painted_wooden_bench", "metal_trash_can", "fire_hydrant", "concrete_road_barrier_02"];
const RAW_DIR = "public/models/props/raw";
const OUT_DIR = "public/models/props";
async function fetchTo(url, path) {
const buf = Buffer.from(await (await fetch(url, { headers: UA })).arrayBuffer());
await mkdir(dirname(path), { recursive: true });
await writeFile(path, buf);
return buf.length;
}
await mkdir(OUT_DIR, { recursive: true });
for (const slug of SLUGS) {
const files = await (await fetch(`https://api.polyhaven.com/files/${slug}`, { headers: UA })).json();
const entry = files.gltf?.["1k"]?.gltf;
if (!entry) { console.warn(`${slug}: keine 1k-gltf-Datei gefunden`); continue; }
const gltfPath = join(RAW_DIR, slug, `${slug}_1k.gltf`);
const gltfSize = await fetchTo(entry.url, gltfPath);
console.log(`${slug}_1k.gltf ${(gltfSize / 1e6).toFixed(2)} MB`);
for (const [relPath, include] of Object.entries(entry.include ?? {})) {
const size = await fetchTo(include.url, join(RAW_DIR, slug, relPath));
console.log(` ${relPath} ${(size / 1e6).toFixed(2)} MB`);
}
const outPath = join(OUT_DIR, `${slug}.glb`);
execFileSync("npx", ["--yes", "@gltf-transform/cli@4.5.0", "optimize", gltfPath, outPath,
"--texture-size", "512", "--simplify-error", "0.01", "--compress", "meshopt"], { stdio: "inherit" });
}