Generic IsaacScript / TypeScriptToLua mod template with a battle-tested, size-optimized Lua
output: enum inlining, require-minimal, single-file bundle, fengari test stack.
Real-project lessons (P0/P1/P2) from DEVELOPMENT_RECOMMENDATIONS.md are baked in: a
zero-lualib util module, an asset pipeline, a purity-guard build test, a differential-test
example, visible plugin warnings, and docs on the hidden-self trap and fengari 32-bit semantics.
npm install
npm run buildnpm run build first runs the asset pipeline (prebuild: copies assets/ and metadata.xml
into mod/), then compiles. Output lives entirely under mod/:
mod/main.lua # single-file bundle
mod/metadata.xml # release manifest (edit it!)
mod/resources/... # copied from assets/
npm run build– asset pipeline + compilesrc/main.tsto optimizedmod/main.luanpm test– code-generation / purity-guard / differential testsnpm run check– build + tests
- Import normal enums from
isaac-typescript-definitions; the bundled plugin inlines them and warns (visible[inlineIsaacEnums]) when an import can't be elided. - Do not import from the
isaacscript-commonbarrel unless you really need it. - Prefer
LuaMap/LuaTable/pairsover JSMap/Set; avoid string indexing /charCodeAt/String.split/Array.sort/Object.keys— they silently pull lualib back into the bundle. Use the zero-lualib helpers insrc/util/lua.tsinstead. - Bit-flag objects (
EntityFlag,ItemConfigTag, ...) are not TS enums: useimport type+ a local constant. - Do not globally enable
noImplicitSelf; Isaac callbacks (and module exports) receive a hidden self argument. SeeOPTIMIZATION_GUIDE.md§4.3. - Pure algorithm/data modules live in
src/core/; the differential-test example (tests/differential-example.test.mjs) shows how to prove a TS port matches a reference Lua implementation in fengari.
See OPTIMIZATION_GUIDE.md (Chinese, detailed) for the full picture.