BLOBBO/src/editor/node-ts-resolve.mjs
type-two 367e700934 Lane J: workshop editor — drop-in GLB fitting on the real course
Three-panel editor page (editor.html + src/editor/): slot list, the actual
greybox course built from the game's own builders, and fit controls. Drop a
.glb on a slot, nudge offset/rotation/scale, save to IndexedDB so the live
game picks it up with no deploy, export manifest.json to commit it.

Design notes worth keeping:
- A custom asset never replaces the procedural node; it goes into a new
  sibling 'fit' node and the original is hidden. Reset is instant, references
  other systems captured stay alive, and the manifest transform lives on a
  node nobody else writes to (feel.ts, telegraph.ts and the machine parts all
  own transforms of their own).
- The stage creates physics but never steps it: no systems, no world.start(),
  just renderOnce() on a rAF. Nothing here affects gameplay.
- A blob body whose UVs paint cannot stick to is refused outright rather than
  swapped in — silently broken paint is worse than a missing model.

Headless verification: 148 assertions across three node test files
(manifest round-trip, GLB paintability against real parsed glTF, and the
whole drop/save/restore path over an in-memory IndexedDB).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 11:40:25 +10:00

34 lines
1.1 KiB
JavaScript

/**
* Lane J — lets node run the repo's extension-less TS imports directly.
*
* The house test style (see paint/coverage-math.test.ts) imports './thing' with
* no extension, which is what tsc's "bundler" resolution and vite both want but
* which node's ESM resolver rejects outright. This registers a resolve hook that
* retries a bare relative specifier as `<specifier>.ts`, so:
*
* node --experimental-strip-types --import ./src/editor/node-ts-resolve.mjs \
* src/editor/manifest-io.test.ts
*
* Plain .mjs on purpose: tsconfig only compiles .ts, and nothing imports this
* file, so it never reaches tsc or the vite bundle.
*/
import { registerHooks } from 'node:module'
registerHooks({
resolve(specifier, context, next) {
try {
return next(specifier, context)
} catch (err) {
if (specifier.startsWith('.') && !/\.[a-z]+$/i.test(specifier)) {
try {
return next(specifier + '.ts', context)
} catch {
// '../machine' style directory imports resolve to their index.ts
return next(specifier + '/index.ts', context)
}
}
throw err
}
},
})