gltf-exporter-node-esm
Done. The solution is built, verified, and documented at ~/bankai/SOLUTION.md.
bankai/
├── SOLUTION.md # title, root-cause analysis, exact fix, verification
├── package.json # "type":"module", three@0.160.0, `bake`/`verify` scripts
├── scripts/
│ ├── bake_models.js # baker: FileReader polyfill, three discovery, file:// imports
│ ├── templates/models.template.js # __MODEL_B64__ marker
│ └── verify_bake.mjs # 6-check verification battery (ALL PASS)
└── src/
├── models.generated.js # 6 base64 payloads injected at the marker
├── models/*.glb # pebble 19.6K, ember 32.4K, runestone 48.6K,
│ # boulder 61.3K, sentinel 117.4K, crag 141.9K
└── load_model.js # GLTFLoader.parse + procedural fallback
examples/jsm/exporters/GLTFExporter.js, its internal import 'three' self-resolves to build/three.module.js, so importing core + addon from the same package yields one shared instance (verified: file:// import === bare 'three' import).FileReader in Node — the exporter reads Blobs via readAsArrayBuffer/readAsDataURL. The subtle trap: it assigns onloadend after readAs*() returns, so the polyfill must read the handler at completion time — a naive capture produces the exact Detected unsettled top-level await hang I hit on the first attempt.NODE_PATH is CJS-only — bare import 'three' fails even with NODE_PATH set (ERR_MODULE_NOT_FOUND). Fix: discover three (BAKE_THREE_ROOT pin → scratch cwd → repo node_modules walk-up) and import via absolute file:// URLs.sizes OK → YES=== disk .glb for all 6; GLB magic/version/length validERR_MODULE_NOT_FOUND (NODE_PATH) and FileReader is not defined capturedBAKE_THREE_ROOT pinning /tmp/three-root# Evidence - Problem class: gltf-exporter-node-esm - Model: openrouter/deepseek/deepseek-v4-flash-0731 - Solved: 2026-08-22T21:59:50.542Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "Baking .glb assets from a Node script with THREE.GLTFExporter (three 0.160): (1) GLTFExporter is an ADDON module \u2014 import separately from examples/jsm/exporters/GLTFExporter.js, same shared three instance (both resolve to build/three.module.js so they share one module instance); (2) the exporter binary path needs a FileReader polyfill in Node (global FileReader = ...); (3) bare three imports do NOT work with NODE_PATH under ESM \u2014 use file:// absolute paths into the three build dir; auto-discover three from scratch dir / repo node_modules / BAKE_THREE_ROOT. Result: scripts/bake_models.js in ~/bankai, 6 .glb files (18-150KB), base64-embedded at __MODEL_B64__ marker, GLTFLoader.parse with procedural fallback in browser.", "environment": "", "language": "", "model": "openrouter/deepseek/deepseek-v4-flash-0731", "problem_class": "gltf-exporter-node-esm", "provider": "openrouter", "solved_at": "2026-08-22T21:59:50.543Z", "version": ""}Done. The solution is built, verified, and documented at ~/bankai/SOLUTION.md.
bankai/
├── SOLUTION.md # title, root-cause analysis, exact fix, verification
├── package.json # "type":"module", three@0.160.0, `bake`/`verify` scripts
├── scripts/
│ ├── bake_models.js # baker: FileReader polyfill, three discovery, file:// imports
│ ├── templates/models.template.js # __MODEL_B64__ marker
│ └── verify_bake.mjs # 6-check verification battery (ALL PASS)
└── src/
├── models.generated.js # 6 base64 payloads injected at the marker
├── models/*.glb # pebble 19.6K, ember 32.4K, runestone 48.6K,
│ # boulder 61.3K, sentinel 117.4K, crag 141.9K
└── load_model.js # GLTFLoader.parse + procedural fallback
examples/jsm/exporters/GLTFExporter.js, its internal import 'three' self-resolves to build/three.module.js, so importing core + addon from the same package yields one shared instance (verified: file:// import === bare 'three' import).FileReader in Node — the exporter reads Blobs via readAsArrayBuffer/readAsDataURL. The subtle trap: it assigns onloadend after readAs*() returns, so the polyfill must read the handler at completion time — a naive capture produces the exact Detected unsettled top-level await hang I hit on the first attempt.NODE_PATH is CJS-only — bare import 'three' fails even with NODE_PATH set (ERR_MODULE_NOT_FOUND). Fix: discover three (BAKE_THREE_ROOT pin → scratch cwd → repo node_modules walk-up) and import via absolute file:// URLs.sizes OK → YES=== disk .glb for all 6; GLB magic/version/length validERR_MODULE_NOT_FOUND (NODE_PATH) and FileReader is not defined capturedBAKE_THREE_ROOT pinning /tmp/three-root# Evidence - Problem class: gltf-exporter-node-esm - Model: openrouter/deepseek/deepseek-v4-flash-0731 - Solved: 2026-08-22T21:59:50.542Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "Baking .glb assets from a Node script with THREE.GLTFExporter (three 0.160): (1) GLTFExporter is an ADDON module \u2014 import separately from examples/jsm/exporters/GLTFExporter.js, same shared three instance (both resolve to build/three.module.js so they share one module instance); (2) the exporter binary path needs a FileReader polyfill in Node (global FileReader = ...); (3) bare three imports do NOT work with NODE_PATH under ESM \u2014 use file:// absolute paths into the three build dir; auto-discover three from scratch dir / repo node_modules / BAKE_THREE_ROOT. Result: scripts/bake_models.js in ~/bankai, 6 .glb files (18-150KB), base64-embedded at __MODEL_B64__ marker, GLTFLoader.parse with procedural fallback in browser.", "environment": "", "language": "", "model": "openrouter/deepseek/deepseek-v4-flash-0731", "problem_class": "gltf-exporter-node-esm", "provider": "openrouter", "solved_at": "2026-08-22T21:59:50.543Z", "version": ""}