MC³ is an experimental Fabric mod for Minecraft 26.2. It replaces full-height streaming with independently addressed 16 x 16 x 16 cubes and provides a layered world generator for vertically stacked terrain profiles.
Published release: 0.3.8 technical preview. The sparse storage, persistence, custom network protocol and three-dimensional tracking foundations are in place, and cube-native light now covers both generation and runtime edits. This release is not acceptance-complete. The remaining blockers include independently convergent Voxy far terrain, cube-native live tick ownership, and configured world generation outside finite level metadata. See STATUS.md and the true-cubic boundary.
TASKS.mdrecords the remaining runtime acceptance gates for this release line.
- Independent
CubePosaddressing, sparse resident storage, custom cube payloads and per-cube persistence. - Buffered view tracking: a square prism — a vanilla-parity Chebyshev square
on X/Z with an independent
verticalViewDistanceY radius at full depth (default-1: follows the horizontal distance) — so the streamed shape always covers the whole client render grid. - Shipped per-cube configured-layer generation through bounded scratch: each
16³ cube receives terrain, structures, decoration and light before first
delivery. The older unified
FULL-column path remains for comparison. - Direct all-air gap generation at legal extreme cube coordinates without allocating a finite compatibility column. Gap biomes are sampled at their absolute quart coordinates.
- A layered generator and world-creation editor for caves, nether, overworld, floating-island and custom profiles.
- Incremental block and block-entity updates, compact per-cube light fields, durable terrain provenance and fail-closed schema-2 compatibility checks.
- Built-in status, pre-generation and profiling commands under
/mc3.
The complete [-30,000,000, 30,000,000) block-coordinate range is valid for
cube addressing, sparse ownership and unconfigured gaps. That does not mean
every runtime subsystem is already full-range. Configured generation still
depends on Minecraft's finite level metadata and bounded compatibility scratch.
Several interaction, light and scheduling paths also retain vanilla packed
coordinate or column boundaries.
Current mod-support boundaries and tested versions are maintained in COMPATIBILITY.md. Release and runtime evidence remains in STATUS.md.
- Minecraft 26.2
- Fabric Loader 0.19.5 or later (the minimum Distant Horizons 3.3.3 needs; the dev environment is pinned to 0.19.5). Distant Horizons 3.3.3 with shaders needs Iris 1.11.4 or later (1.11.2 crashes); its BLAZE_3D renderer works only without Iris, while OPEN_GL works with Iris. See
COMPATIBILITY.md - Fabric API 0.155.2+26.2 or a later 0.155.x build for Minecraft 26.2
- Java 25
The archived 0.3.6 JAR's Fabric metadata used a wildcard for Fabric API even
though this is the validated range. The 0.3.7 source enforces
~0.155.2+26.2; its final packaged load proof remains part of the release
gate.
Replace your-session with one unique, shell-safe identifier. First save this
as /tmp/mc3-your-session.init.gradle so every project's build output is kept
off the unreliable checkout mount:
def mc3BuildRoot = new File(System.getProperty('mc3.buildRoot'))
gradle.beforeProject { project ->
def relative = project.path == ':' ? 'root' : project.path.substring(1).replace(':', '/')
project.layout.buildDirectory.set(new File(mc3BuildRoot, relative))
}flock --wait 7200 /tmp/mc3-build.lock \
./gradlew clean build --project-cache-dir /tmp/mc3-pcache-your-session \
--init-script /tmp/mc3-your-session.init.gradle \
-Dmc3.buildRoot=/tmp/mc3-build-your-session \
--no-build-cache --no-daemon --console=plainThat local command writes the mod jar to
/tmp/mc3-build-your-session/root/libs/mc3-<version>.jar; CI's default output
remains build/libs/. The wrapper pins Gradle 9.5.1 by SHA-256 and the build
uses the stable Fabric Loom 1.17.18 plugin. GitHub Actions runs the clean build
on Java 25.
Useful local verification commands are:
export MC3_GRADLE_EXTRA_ARGS='--project-cache-dir /tmp/mc3-pcache-your-session --init-script /tmp/mc3-your-session.init.gradle -Dmc3.buildRoot=/tmp/mc3-build-your-session --no-build-cache'
flock --wait 7200 /tmp/mc3-build.lock \
./gradlew clean build --project-cache-dir /tmp/mc3-pcache-your-session \
--init-script /tmp/mc3-your-session.init.gradle \
-Dmc3.buildRoot=/tmp/mc3-build-your-session \
--no-build-cache --no-daemon --console=plain
tools/mixin-loadtest.sh
MC3_SMOKE_MODE=per_cube tools/true-cubic-smoke.sh
MC3_SMOKE_MODE=unified tools/true-cubic-smoke.sh
MC3_SMOKE_MODE=deferred tools/true-cubic-smoke.shtools/smoke-server.sh is a destructive regression harness for its own
run/world fixture. Read the script and STATUS.md before invoking it.
One chunk column (16×16×384) equals 24 cube-equivalents (16³), so all three targets are directly comparable:
| Target | Fill time | Volume delivered | Delivery rate |
|---|---|---|---|
| Vanilla 26.2 | 7.75 s | 6,936 cube-equivalents (289 columns × 24) | 895 cube-equiv/s |
| MC³ (halo) | 69.1 s | 6,137 cubes | 89 cubes/s |
| MC³ (batch) | 59.4 s | 6,137 cubes | 103 cubes/s |
| MC³ (spill) | 60.5 s | 6,137 cubes | 114 cubes/s |
Restated on equal volume: vanilla covers MC³'s entire 6,137-cube window in
~6.9 s; batch narrows the gap to ~8.7× and spill to ~8.1×. Same GPU rig and client pin, fresh world per run
(seed 20260831); "fill" = the full view window delivered (first delivery to
window complete); halo/batch/spill are decoration strategies (config/mc3.json
decorationStrategy); the spill row is from the 21 September #233 three-way
round, which re-measured halo/batch alongside it on the same scenario state
(first→last send 73.5 s / 64.6 s, one run per arm, ~6% run-to-run noise).
Plays the SAME scenarios on unmodified vanilla 26.2 and on MC³ with
identical client-side instrumentation, and reports lag spikes + chunk
render-in. No fix changes; findings land in docs/LAG-PROFILE-244.md.
tools/stage-vanilla-fixture.sh # one-time vanilla existing-world fixture
./gradlew -p tools/render-bench-mod build # measurement mod (mc3bench-0.1.0.jar)
tools/render-lag-harness.sh --target vanilla --label vanilla-1 --scenario all
tools/render-lag-harness.sh --target mc3 --mc3-strategy halo --label mc3-halo-1 --scenario all
tools/render-lag-harness.sh --target mc3 --mc3-strategy batch --label mc3-batch-1 --scenario all
tools/render-lag-matrix.sh # interleaved 3-run matrix
python3 tools/render-lag-report.py combined --out docs/LAG-PROFILE-244.md
Both arms: 8-CPU pin (0-7), 24/32 GiB cgroup, 12 GiB heap, exclusive Xvnc
:99 lease, JFR + gc log, per-run host-load samples. The bench mod
(tools/render-bench-mod, no fabric-api dependency) instruments frame
times + hitch buckets, client tick durations, chunk mesh events with
positions (vanilla renderer path on vanilla, Sodium build results on
MC³), received chunk packets and 1 Hz heap/GC samples to per-run JSONL +
summary. Scenario phases: existing-world join (120 s), two new-chunk
teleport hops (60 s each), idle settle (60 s). Run artefacts land under
/tmp/mc3-lagprof244/runs/<label>/.
For a dedicated server, set this in server.properties:
level-type=mc3\:cubicFor single-player, choose MC³ Cubic on the World screen. The Customise screen edits the overworld layer stack; JSON import/export covers the complete dimension set. See docs/WORLDGEN_PRESETS.md.
Open Options > MC³ Settings. The main screen has six controls plus an Advanced… entry; each tooltip says what the setting does, what it costs and whether it applies now or on the next world load.
| Control | What it sets |
|---|---|
| Performance preset | Performance / Balanced / Quality (Balanced = the shipped defaults). It is a view over generation speed, far terrain sends per tick, far terrain trees, exact far sky and the cube update budget, and shows Custom whenever any of those differs from a preset. |
| Vertical view distance | Auto (follows render distance) or 2..16 cubes. |
| Far terrain | Off, Auto (follows Voxy's own render distance, then Distant Horizons' lodChunkRenderDistanceRadius, then Voxy World Gen V2's radius, then 128; capped at 128 chunks) or 16..256 chunks manually. Greyed out with "No LOD mod installed (Voxy or Distant Horizons)" when neither is present. |
| Generation speed | Gentle / Normal / Fast: background worker count (8 / automatic / automatic) plus the deferred-band concurrency caps. |
| Save safety | Immediate (safer, the default) or Fast (fastSaves: defers the authoritative write to the next autosave or quit; a crash rolls back to that barrier). |
| Cube debug overlay | The #250 load-state overlay master toggle. |
Preset values:
| Preset | Generation speed | Far sends/tick | Cube updates/tick | Far trees | Exact far sky |
|---|---|---|---|---|---|
| Performance | Gentle (8 workers, 32 active, 24 starts/tick) | 24 | 2048 | off | off |
| Balanced | Normal (automatic workers, 48, 48) | 40 | 4096 | off | off |
| Quality | Fast (automatic workers, 64, 64) | 64 | 4096 | on | on |
Advanced… (Technical) holds the decoration strategy, far terrain trees, exact far sky, the worker CPU reservation (affinity), the cube update budget and an entry to the per-state overlay toggles and colours. Rows that the server governs are disabled while connected to a remote server.
config/mc3.json is version 2 and is grouped by _comment entries (ignored on
read) into player-facing, advanced and developer keys:
{
"configVersion": 2,
"_comment_player": "...",
"verticalViewDistance": -1,
"farTerrainDistance": -1,
"fastSaves": false,
"debugCubeStateOverlay": false,
"_comment_advanced": "...",
"decorationStrategy": "halo",
"farLodDecorate": false,
"farLodExactSky": false,
"worldgenWorkerAffinity": "",
"worldgenBackgroundWorkers": 0,
"maxCubeUpdatesPerTick": 4096,
"farLodSendsPerTick": 40,
"generationConcurrency": 48,
"generationStartsPerTick": 48,
"_comment_developer": "...",
"generationMode": "per_cube",
"suppressHaloColumnGeneration": true,
"windowedColumnSections": true,
"haloColumnsPrimaryBandOnly": true,
"elideCanonicalAirSections": true,
"stubCoveredColumnSaves": true,
"skipCubeOwnedColumnSaveLight": true,
"skipGenerationOnlyColumnSaves": true,
"debugCubeTraffic": false
}(The real file also lists the overlay per-state settings and the remaining
far-LOD tuning constants.) farTerrainDistance is -1 for Auto, 0 for Off,
otherwise chunks (one chunk is one cube horizontally); it replaces
farLodEnabled, voxyViewDistance and farLodRadius, and the far-feed radius
follows it, capped at 128 cubes. Auto reads sectionRenderDistance from
config/voxy.json (Voxy shows sectionRenderDistance * 32 chunks).
Migration. A version 1 file is migrated on first load: the original is kept
once as mc3.json.v1.bak, unknown keys are preserved, and each mapping is
logged (Config migration: ...). The legacy keys remain readable for two
releases when the new key is absent: farLodEnabled=false or
voxyViewDistance=0 becomes farTerrainDistance=0, a positive farLodRadius
becomes that distance, anything else becomes Auto;
maxActiveLayerGenerations, maxLayerGenerationStartsPerTick and
maxQueuedLayerGenerations become generationConcurrency,
generationStartsPerTick and generationQueueLimit; unifiedGeneration only
derives generationMode when that is absent, then is dropped. A combination of
values that matches no preset simply shows as Custom with every value kept.
The three generation* limits are read by generationMode="deferred_band"
only; the per-cube pipeline ignores them (it is bounded by the worker pool).
When -Dmc3.fastSaves, -Dmc3.worldgen.backgroundWorkers or
MC3_WORKER_AFFINITY override the config, the log states the effective value
and its source.
verticalViewDistance defaults to -1, which follows the horizontal
distance so the streamed prism covers the whole client render grid; an
explicit value is clamped to 2..64. The far-feed radius (resident cubes
inside the far distance but outside the streamed view, pushed to the client's
Voxy LOD database) never starts far generation by itself — deliberate far
pre-fill is /mc3 pregen's job. This is not Voxy's own render distance:
Voxy 0.2.18's packed LOD identity represents section Y -128..127 only.
maxCubeUpdatesPerTick is clamped to 1..4096. Deferred generation limits are
clamped to a queue of 1..65536, active work of 1..64, and starts of
1..active.
generationMode="per_cube" is the shipped path: one 16³ cube at a time,
decorated and lit before first delivery, with no full-depth column held
resident for delivered content. unified (the pre-0.3.0 shipped path) and
deferred_band remain selectable for comparative testing; both require
decoration to be part of the result before the first payload, and deferred
delivery fails closed until its decoration result is ready. The legacy
unifiedGeneration boolean still maps onto these modes for old configs
(read for migration only; it is no longer written).
decorationStrategy (per-cube pipeline only, TASKS #233) picks how the
decoration kernel is grouped and when decorated cubes become deliverable:
halo (default) decorates each cube's 3×3 column tile at the cube's own Y
exactly as always; batch decorates one 3×3×3 cube group per pass — the
neighbour halo and feature setup are paid once per group and all 27 cubes
are released with complete payloads together (a group's cubes become
deliverable in the same prepare pass); spill shares batch's band-aligned
passes as the shared deterministic anchor evaluation (each pass a pure
function of tile anchor, band and world seed) but assembles and releases
every cube independently, so a spill cube becomes deliverable the moment
its own noise, features and light are done — no group admission, no batch
coupling. halo, batch and spill are content-identical for the same
seed (pinned by block-for-block parity tests, including a forest region
straddling four tiles and a structure-bearing region whose mineshaft start
reaches across column boundaries). The strategy is read strictly once per
world load; switching it across a reload never re-generates
already-generated cubes — it applies only to not-yet-generated ones.
Surface: the config/mc3.json key, Options > MC³ Settings > Advanced…,
plus worldgen.decoration= in /mc3 status (the Customise screen edits layer
stacks, not pipeline strategy).
The 0.3.7 source contains additional terrain/closure parity, full-domain light-node identity, C2ME and Voxy capacity work, but none of it is a released 0.3.6 guarantee. Fresh same-seed cross-path parity, repeat determinism, the current performance baseline, the top/bottom runtime-light warning census, the C2ME three-way runtime matrix and Voxy's radius-63 GPU run remain acceptance work.
Five memory behaviours ship default-on, each decodable to false for
comparative debugging: suppressHaloColumnGeneration (the vanilla
47×47 player-ticket column halo is never materialised for cubic levels —
rig-measured ~3 GB of full-depth columns; streamed columns stay
entity-ticking via MC³'s own residency tickets), windowedColumnSections
(persisted, non-referenced content sections of FULL columns become
biome-exact placeholders until their cube is demanded again),
haloColumnsPrimaryBandOnly (in per-cube mode, columns driven purely by
vanilla ticket propagation generate only the primary surface band rather
than every configured layer at full depth), elideCanonicalAirSections
(canonical all-air sections are elided from region saves with a
marker-driven exact restore), and stubCoveredColumnSaves (cube-covered
column slots are saved as metadata-only stubs — air states plus the real
biome container — with content served by the cube store; fail-closed, so
placeholder air never reaches disk over real content).
The stable mc3-test.mrpack is published on the project's
GitHub Releases. Release
0.3.8-test.1 contains MC³, Fabric API, Sodium, Iris and Voxy for Minecraft
26.2. Shaders start disabled. Set the launcher's maximum memory to 12288 MiB
(12 GiB) after import because the Modrinth pack format does not carry a JVM
memory setting; 8 GiB is workable for settled play and 6 GiB is tight during
roam transients. The setting matters: the settled live set is only about
1.5 GiB, so a near-default launcher heap leaves almost no headroom for roam
or generation bursts. Measured on this profile's fresh-world 11,109-cube
backlog: a 6.1 GiB ceiling turned the burst into 12 full garbage collections
of about 500 ms each, while 12 GiB absorbs it with no full collections
(worst stop-the-world pause 126 ms). The mod checks the heap at client
startup: below 12 GiB it logs this guidance, and below 8 GiB it also shows a
one-time in-game chat warning.
The immutable 0.3.6 profile's embedded MC3-PROFILE-SETUP.txt predates the
memory correction and incorrectly says 64 GiB and a 32-cube MC³ far feed. Do
not follow those two lines: the current guidance is 12 GiB and
voxyViewDistance=64. The archive is not rewritten; 0.3.7 and later embed the
corrected setup prose.
Voxy's inclusion is intentional. A release cannot pass by excluding a broken mandatory compatibility path. The profile is therefore a review and correctness-testing surface, not evidence that all current blockers are fixed.
To capture a performance problem in a world:
/mc3 profile start 60
MC³ writes a JFR recording and JSON summary under the instance's debug/
directory.
- The isolated
buildcommand above proves compilation and automated tests. It does not prove a join, renderer, save/reload or full-range runtime path. tools/mixin-loadtest.shboots the real Fabric client loader without a display and transforms the packaged Sodium, Iris and Voxy profile. It does not prove graphical correctness.tools/true-cubic-smoke.shuses an isolated temporary world and checks generation classification, sparse ownership and persistence at coordinate edges. Its defaultper_cubemode gates the shipped path;unifiedanddeferredremain available as comparative modes.- The GPU-backed client rig is required for join flow, movement, input,
rendering and visual first-delivery checks. Current evidence and any
omissions are recorded in
STATUS.md.
Release acceptance still requires authoritative cube-native ticks, entities and points of interest; independently convergent Voxy far terrain; stable Sodium behaviour over travel; and no dependence on lossy vanilla packed Y coordinates in the accepted paths.

