The core monorepo for MCX β a domain-specific language (DSL) for building Minecraft Bedrock Edition (MCBE) addons.
Disclaimer: MCX is not affiliated with or endorsed by Mojang/Microsoft. It is an independent, community-driven project.
| Language | Link |
|---|---|
| δΈζ | ./docs/README.zh.md |
| νκ΅μ΄ | ./docs/README.ko.md |
| ζ₯ζ¬θͺ | ./docs/README.ja.md |
MCX is a DSL that compiles .mcx source files into MCBE-compatible JSON components, UI forms, and event systems. It lets you build Minecraft Bedrock addons in a simple, declarative, and type-safe way β without hand-writing hundreds of JSON files.
The pipeline: .mcx file β parser β AST β transform (Babel) β compiled JS β MCBE JSON.
- Component MCX β Generate MCBE component JSON (items, blocks, entities) fast and declaratively
- Form MCX (
<Form>) β Build in-game forms using traditional FormData (ModalFormData / ActionFormData / MessageFormData) - UI MCX (
<Ui>) β Build in-game CustomForm UIs with Observable reactive binding (DDUI) - Explicit form type β Set
type="modal|action|message"on<Ui>or<Form>to override heuristic detection - Nested UI elements β Child elements recursively flattened; grouping containers supported
forloops within/ofβ Iterate over arrays in templates withfor="item in items"orfor="item of items"- Setup system β
<Form setup>/<Ui setup>auto-collect declarations, no manualexportneeded definePropmacro β Compile-time prop declarations with defaults- Lifecycle hooks β
onStartup(once) andonMounted(per show) for setup logic - Event MCX β Subscribe to and handle game events cleanly
- App MCX β Tie components, UI, and events together into a runnable app
- MCX Client β Runtime framework (
createApp,Event,ui,Utils) that runs your app in-game - MCX Compiler β Core compiler with Rollup/Rolldown plugin support, paired with mbler for project scaffolding and builds
- Type-safe β Full TypeScript type definitions for all Minecraft component options, sound events, particle types, and more
- I18n β Built-in internationalization support (en / zh / ja / ko)
- Image assets β PNG, JPG, SVG, and GIF image components for texture generation
This is a pnpm workspace monorepo containing the following packages:
| Package | Version | Description |
|---|---|---|
@mbler/mcx-core |
The DSL compiler β parser, AST, transform pipeline, and Rollup/Rolldown plugins | |
@mbler/mcx |
Runtime framework β createApp, Event, ui, Utils |
|
@mbler/mcx-types |
Shared TypeScript type declarations for MCBE JSON formats | |
@mbler/mcx-component |
Component runtime classes (Item, Block, Entity, Image) used at compile time | |
create-mbler |
CLI scaffolding tool for new mbler projects |
mcx-core/
βββ packages/
β βββ core/ # @mbler/mcx-core β DSL compiler (parser β AST β transform β codegen)
β βββ client/ # @mbler/mcx β runtime framework (createApp, Event, UI)
β βββ types/ # @mbler/mcx-types β shared TypeScript type declarations
β βββ mcx-component/ # @mbler/mcx-component β component runtime classes (Item, Block, Entity, Image)
β βββ create-mbler/ # create-mbler β CLI scaffolding tool for new mbler projects
βββ docs/ # README translations (zh, ja, ko) + TODO.md
βββ scripts/ # verify-commit.js (commit-msg hook)
βββ .github/workflows/ # CI (pnpm install β lint:packages β test)
Below is a complete example showcasing all four MCX file types β Component, Event, UI, and App.
<Component>
<items>
<item id="sword.json">sword</item>
</items>
</Component>
<script lang="ts">
import { ItemComponent } from "@mbler/mcx-component";
export const sword = new ItemComponent({
id: "demo:custom_sword",
name: "Custom Sword",
components: {},
});
sword.setDam
</script><Event @after>
playerJoin = onPlayerJoin
</Event>
<script lang="ts">
import { world } from "@minecraft/server";
import { showForm } from "@mbler/mcx";
import form from "../ui/greeting.mcx"
export function onPlayerJoin(event: PlayerJoinAfterEvent) {
const player = world.getPlayers({
name: event.playerName
});
player.sendMessage("Welcome to the server!");
showForm(form, player, {
playerName: event.playerName
})
}
</script>Use <Form> for traditional FormData (ModalFormData / ActionFormData / MessageFormData):
<Form>
<label>{{ playerName }}!</label>
<label>Hello</label>
<button click="onClick">Close</button>
</Form>
<script lang="ts">
export function onClick() {
// close the form
}
</script>Use <Ui> for new CustomForm with Observable reactive binding:
<Ui setup>
<title>Settings</title>
<input>{{ name }}</input>
<toggle>{{ enabled }}</toggle>
<button click="handleSave">Save</button>
</Ui>
<script>
import { onMounted, onStartup } from "@mbler/mcx";
const name = defineProp('Player')
const enabled = defineProp(true)
onStartup(() => {
// runs once on first show
})
onMounted(() => {
// runs every time form is shown
})
function handleSave() {
// name.getData() gets current value
}
</script><script lang="ts">
import event from "./events/player_join.mcx";
event.subscribe();
// also can use: event.subscribe("playerJoin")
</script>import app from "./app.mcx";
import { createApp } from "@mbler/mcx";
import { world } from "@minecraft/server";
createApp(app).mount(world);More Usage See Bedwars Addon
# Using the create-mbler CLI
pnpm create mbler# Install the compiler and runtime
pnpm add -D @mbler/mcx-core
pnpm add @mbler/mcxThen configure your bundler (Rollup/Rolldown) with the MCX plugin and start writing .mcx files.
For full documentation and tutorials, visit the Docs.
| Layer | Technology |
|---|---|
| Language | TypeScript (strict mode) |
| Package manager | pnpm 11 |
| Build | Rolldown |
| Bundler plugins | Rollup / Rolldown plugin for .mcx files |
| AST | Babel (@babel/parser, @babel/generator, @babel/types) |
| Type system | @volar/language-core for language service |
| Testing | Vitest |
| Linting | ESLint + Prettier |
| CI | GitHub Actions |
# Install dependencies
pnpm install
# Build all packages
pnpm build
# Run tests
pnpm test
# Lint all packages
pnpm lint:packages
# Full check (lint + test + typecheck)
pnpm check
# Format code
pnpm formatContributions are welcome! Please read the Contributing Guide before submitting a pull request.
Before committing, make sure to run:
pnpm checkCommit messages must follow the conventional commits standard (enforced via git hooks).