Skip to main content

generator

Write Minecraft JSON as TypeScript. The filter finds .ts files in your packs, runs them, and writes the JSON next to them — one file, or many from a list. Templates are checked against Mojang's official JSON Schemas as you type.

Install​

regolith install generator
config.json
{
"regolith": {
"profiles": {
"build": {
"filters": [{ "filter": "generator" }, { "filter": "bundler" }]
}
}
}
}

Inside the core stack it runs only when its key is present, because it writes schema types into the project. Add generator to core's settings, true for the defaults or an object with the settings below; core runs it after manifest and before the bundler:

config.json
{ "filter": "core", "settings": { "generator": true } }

Then add the generated types to tsconfig.json:

tsconfig.json
{
"include": [
"packs/data/generated/mc/globals.d.ts",
"packs/BP/**/*.ts",
"packs/RP/**/*.ts"
]
}

Run the build once — the types are written on the first run.

Authoring​

One file​

A default-exported object becomes one .json with the same basename — training_dummy.entity.ts writes training_dummy.entity.json beside it. satisfies Entity is what gives you autocompletion; it is erased at build time, so nothing reaches the runtime.

BP/entities/training_dummy.entity.ts
export default {
format_version: '1.21.0',
'minecraft:entity': {
description: { identifier: 'example:training_dummy', is_summonable: true },
components: {
'minecraft:health': { value: 20, max: 20 },
'minecraft:physics': {},
},
},
} satisfies Entity;

Many files​

Default-export [nameFn, dataFn, items] — ores.ts below writes ruby_ore.json and sapphire_ore.json. nameFn returns a basename (.json is added if missing); both callbacks may be async.

BP/blocks/ores.ts
type Options = { id: string; mapColor: string; light?: number };

export default [
(o) => `${o.id}.json`,
(o) => ({
format_version: '1.21.0',
'minecraft:block': {
description: { identifier: `example:${o.id}` },
components: {
'minecraft:map_color': o.mapColor,
'minecraft:light_emission': o.light ?? 0,
},
},
}),
[
{ id: 'ruby_ore', mapColor: '#c0392b' },
{ id: 'sapphire_ore', mapColor: '#2980b9', light: 7 },
],
] satisfies Many<Options, Block>;

Naming Options once in the satisfies types both callbacks, so o needs no annotation.

The type names​

One global per document category, no import needed. Press Ctrl+Space after satisfies to browse all 39:

Block Entity Item Biome Feature FeatureRule LootTable Recipe SpawnRule Trading Dialogue AnimationController VoxelShape Tick Model Fog Particle Attachable RenderController Sound BlocksResource TerrainTexture ItemTexture FlipbookTexture BlockCulling Ui GlobalVariable TextureSet Language MusicDefinition Lighting ColorGrading Atmospheric Pbr PointLight Shadow Water

Two carry a pack prefix because the plain name was taken: BpAnimation (TypeScript's DOM lib defines Animation) and RpEntity. If any of these clash with your own globals, set typePrefix — "Mc" gives McBlock, McEntity, and so on.

Rules​

  • Templates live anywhere under BP/RP, at any depth. BP/entities/mobs/hostile/zombie.ts works; its JSON is written beside it. The type comes from satisfies, never from the folder.
  • BP/scripts/** and **/*.d.ts are skipped.
  • No import or require at runtime — templates are evaluated in a sandbox. import type is fine (esbuild erases it), so you can pull in type names directly: import type { BlockBehaviorDocument } from '../../data/generated/mc'.
  • Pack folders come from config.json (packs.behaviorPack / packs.resourcePack), defaulting to BP and RP.

What it generates​

OutputWhereCommit it?
One .json per template, or per item of a Many listbeside the template, in the temp workspaceno
globals.d.ts and the schema .d.ts files<dataPath>/generated/mc in the real projecteither — they never ship, and they are rewritten when the schema version changes

The filter downloads @minecraft/bedrock-schemas, caches it under .regolith/cache/generator/, and compiles it into .d.ts files, skipped when the cached version already matches. Then it scans for templates, transpiles each with esbuild, evaluates it in a sandboxed VM, and writes the JSON. The types land in the real project because the IDE is what reads them.

The schemas trail the game by a version or two, so strict is off by default. Where a schema carries no usable information — a few components are published as a bare {"type": "object"}, and entity description is undescribed — the type is unknown rather than an invented shape, so valid templates never produce false errors. Component names autocomplete everywhere; some values are unconstrained.

Settings​

SettingTypeDefaultDescription
includestring | string[]["BP/**/*.ts", "RP/**/*.ts"]Globs to scan
excludestring | string[]["BP/scripts/**", "**/*.d.ts"]Globs to skip
prettyfalse | { indent?, size? }falseHow generated JSON is laid out. Absent or false writes it minified. An object lays it out: indent is "tab" or "space", size the characters per level (2 for spaces, 1 for tabs when omitted)
typesbooleantrueGenerate the Minecraft types. false skips the download entirely
schemaVersionstring"latest"Dist-tag (latest, beta) or exact version. Pin it for reproducible builds
typesDirstring<dataPath>/generated/mcWhere the types land, relative to the project root
typePrefixstring""Prefix for the global aliases
strictbooleanfalseReject properties the schema does not declare
maxAgeHoursnumber24Registry metadata cache lifetime. Only used for dist-tags

Checks​

MessageFix
ROOT_DIR environment variable not setRun through Regolith; the filter needs its environment
No .ts templates foundTemplates must be under BP/RP and not in BP/scripts/
Imports are not allowed in template filesDrop the import / require, or make it import type
Invalid default export arrayThe tuple must be exactly [nameFn, dataFn, items]
Invalid filenamenameFn must return a non-empty basename, no directories
Cannot find name 'Block'tsconfig.json include is missing packs/data/generated/mc/globals.d.ts, or the build has not run yet
Types look staleBump schemaVersion, or delete packs/data/generated/mc/