bedrock-render exposes five layers:
RenderPalettefor color lookup, overrides, and JSON imports.MapRendererfor tile, batch, region, bake, and web-map rendering.MapRenderSessionfor long-lived interactive renderers with cache reuse and streaming tile events.bedrock_render::editorfor explicit v0.2.0 writable map tooling overbedrock-worldmap/global/HSA/actor/block-entity/heightmap/biome records.- Value types for layout, threading, memory budgets, diagnostics, and cached tile paths.
Create a lazy bedrock_world::BedrockWorld, then pass it with a palette to
MapRenderer::new:
use std::sync::Arc;
let world = bedrock_world::BedrockWorld::open_blocking(
"path/to/minecraftWorld",
bedrock_world::OpenOptions::default(),
)?;
let renderer = bedrock_render::MapRenderer::new(
Arc::new(world),
bedrock_render::RenderPalette::default(),
);RenderPalette::default() builds the palette from embedded auditable JSON
sources at startup. Applications that carry their own licensed color data can
merge additional JSON before constructing the renderer.
Use RenderJob::new for one tile and MapRenderer::plan_region_tiles for
deterministic web-map regions. RenderLayout controls world coverage and pixel
density. RenderOptions controls output format, backend, threading, memory
budget, CPU/GPU pipeline policy, priority, diagnostics, cancellation, and
surface shading.
ImageFormat::Rgba is the cheapest validation format. ImageFormat::WebP and
ImageFormat::Png populate TileImage::encoded when their features are enabled.
Use MapRenderSession for UI integrations. The session owns a MapRenderer,
shares a memory/disk tile cache, and can use render-index culling to avoid
loading chunks that have no renderable records.
let session = bedrock_render::MapRenderSession::new(
renderer,
bedrock_render::MapRenderSessionConfig {
cache_root: "target/render-cache".into(),
world_id: "world".into(),
world_signature: "stable-content-signature".into(),
cull_missing_chunks: true,
..Default::default()
},
);
let cancel = bedrock_render::RenderCancelFlag::new();
session.render_web_tiles_streaming_blocking(
&planned_tiles,
bedrock_render::RenderOptions {
cancel: Some(cancel),
cache_policy: bedrock_render::RenderCachePolicy::Use,
..Default::default()
},
|event| {
match event {
bedrock_render::TileStreamEvent::Cached { .. } => {}
bedrock_render::TileStreamEvent::Rendered { .. } => {}
bedrock_render::TileStreamEvent::Failed { .. } => {}
bedrock_render::TileStreamEvent::Progress(_) => {}
bedrock_render::TileStreamEvent::Complete { .. } => {}
}
Ok(())
},
)?;render_web_tiles_streaming is available with the default async feature. It
wraps the same blocking pipeline in tokio::task::spawn_blocking. For UI code
that prefers an async channel, use render_web_tiles_streaming_channel; it
returns a tokio::sync::mpsc::Receiver<TileStreamEvent> immediately and lets
the render task continue in the background.
Rendering remains read-only by default. Use bedrock_render::editor only for
explicit write-mode workflows. The module re-exports the common bedrock-world
v0.2 map/global/HSA/actor/block-entity/heightmap/biome/query/write-guard types
and adds two render-facing helpers:
MapWorldEditoropens or wraps a writableBedrockWorldand exposes common structured editor calls.MapEditInvalidationdescribes which metadata, overlays, chunks, and tile caches must be refreshed after a write.
use bedrock_render::editor::{MapWorldEditor, WorldScanOptions};
let editor = MapWorldEditor::open_writable("path/to/minecraftWorld")?;
let maps = editor.scan_map_records(WorldScanOptions::default())?;
let overlays = editor.scan_hsa_records(WorldScanOptions::default())?;
let invalidation = editor.put_heightmap(chunk_pos, chunk_version, &heightmap)?;
if invalidation.refresh_metadata() {
// reload metadata panels or manifest-derived summaries
}
for chunk in invalidation.affected_chunks() {
// remove cached tiles covering this chunk and schedule rerender
}MapWorldEditor intentionally does not replace the full bedrock-world API.
Use the facade for common map viewer actions such as map/global records, HSA,
modern actors, block entities, heightmaps, and biome storage. Use
editor.world() or bedrock-world directly for uncommon Bedrock records or
tool-specific validation. Applications should still require a per-operation
confirmation before mutating methods and should increment UI generations before
refreshing overlays or tiles so stale background results are ignored.
render_web_tiles_blockingremains suitable for static exports where one sink writes all tiles.- Interactive renderers should use
MapRenderSessionand stream events into the UI. - Full-world chunk scans should move to
bedrock-worldrender-index APIs before planning visible tiles. render_web_tiles_blockingremains ordered for export. For first-screen interactivity, setRenderOptions::prioritytoRenderTilePriority::DistanceFrom { tile_x, tile_z }.
RenderOptions::cpu controls the local Rayon pipeline used for load, bake,
compose, and encode coordination:
queue_depth=0picks a bounded queue sized to the worker count and work set.chunk_batch_size=0letsbedrock-worldchoose render chunk batch sizes.encode_workers=0keeps encode/write workers profile-aware.
The renderer does not use Rayon global pool state. Long-lived sessions reuse the same world, renderer, cache, and diagnostics path while each render request keeps cancellation and progress scoped to its generation.
SurfaceBlocksis the primary terrain map.HeightMaprenders height gradients from the computed surface columns used by terrain rendering.RawHeightMaprenders raw Bedrock Data2D/Data3D/Legacy heightmap records for diagnostics and migration checks.Biome { y }renders resolved biome colors at a sampled Y layer.RawBiomeLayer { y }renders diagnostic biome-id colors.LayerBlocks { y }renders a fixed X/Z block layer.CaveSlice { y }renders air, solid, water, and lava diagnostics for a fixed Y layer.
Missing chunks and empty terrain are transparent. Unknown block names are opaque diagnostic pixels.
SurfaceBlocks and HeightMap use bedrock-world exact surface sampling:
actual block columns are scanned top-down and baked as a canonical
TerrainColumnSample contract with the visual surface block, relief support,
thin overlay, and water context. Saved heightmaps are still loaded, but they
are treated as hints/diagnostics and can disagree with the rendered surface.
Use RawHeightMap when you need the old raw-height diagnostic image.
Old Bedrock/Pocket Edition chunks may expose only LegacyTerrain tag 0x30.
bedrock-render handles this through bedrock-world render exact-batch loading:
SurfaceBlocksscans the legacy0..=127height range from actual block IDs.HeightMapcolors the computed legacy surface height over0..=127.RawHeightMapcolors the saved legacy heightmap over0..=127.LayerBlocksandCaveSlicesample legacy block ID + data arrays directly.- Common 0.16 numeric block IDs are mapped to modern
minecraft:*names before palette lookup; unknown IDs becomelegacy:<id>and are counted by diagnostics. - Legacy biome samples are decoded as
[biome_id, red, green, blue].Biomerenders saved RGB directly and prefers it over conflicting old Data2D/Data3D biome ids.RawBiomeLayeruses the saved biome ID when the palette knows it and falls back to saved RGB for unknown old IDs. SurfaceBlocksuses legacy RGB samples for grass and foliage tint. Water keeps the normal water-tint fallback so legacy grass colors are not applied to water.- If a transition chunk has both
LegacyTerrainandSubChunkPrefix, subchunk block data wins and legacy terrain is only a fallback for missing block data.
The renderer cache version is RENDERER_CACHE_VERSION = 48, so old
transparent, incorrectly sampled, raw-height-driven, misplaced region-compose,
renderer-rescanned, or incorrectly prioritized legacy-biome tiles are not
reused. RenderOptions::default() bypasses tile cache reads/writes; opt in
with RenderCachePolicy::Use when a session or export should use the cache.
MapRenderSession::new also lifts stale lower renderer versions to the current
version before creating cache keys.
RenderPipelineStats exposes placement diagnostics for web/region pipelines:
region_chunks_copied, region_chunks_out_of_bounds, and
tile_missing_region_samples. Non-zero out-of-bounds or missing-region sample
counts indicate a planning/compose contract problem rather than a LevelDB read
failure.
All public fallible APIs return bedrock_render::Result<T>.
Match BedrockRenderError::kind() for stable categories:
match error.kind() {
bedrock_render::BedrockRenderErrorKind::Cancelled => {
// The caller's cancel flag was observed.
}
bedrock_render::BedrockRenderErrorKind::UnsupportedMode => {
// The requested output format or feature is not enabled.
}
_ => eprintln!("{error}"),
}Display strings are for humans and may become more descriptive over time.
The default feature set includes gpu. RenderBackend::Auto now attempts GPU
compose for tiles at or above RenderGpuOptions::min_pixels, then falls back to
CPU when the GPU feature, adapter, tile shape, or shader path is unavailable.
RenderBackend::Gpu forces the attempt. RenderGpuFallbackPolicy::Required
turns these fallback cases into errors instead of CPU renders. GPU failures are
reported through RenderPipelineStats::gpu_fallback_reason and counted as CPU
fallback renders.
RenderOptions::gpu controls scheduling:
min_pixelsis the Auto-mode threshold before GPU compose is attempted.backendselectsautoor thewgpubackend.fallback_policyselects CPU fallback or strict required GPU execution.diagnosticsselects off, summary, or verbose GPU logs through thelogfacade.max_in_flight=0uses profile defaults: up to 4 interactive jobs or 8 export jobs.batch_size=0,batch_pixels=0,submit_workers=0, andreadback_workers=0use profile-aware automatic defaults.buffer_pool_bytes=0andstaging_pool_bytes=0enable automatic reusable storage/readback pool budgets. Explicit non-zero values cap each pool.
The GPU path uses a single wgpu device with a bounded in-flight queue. CPU
workers continue to load, bake, and prepare tiles while GPU jobs upload,
dispatch, and read back results. Web/region ready tiles are submitted through a
true batch path, so batch_size and batch_pixels affect submit/readback
counts. Stats expose selected backend, adapter name/vendor/device type,
gpu_supported_tiles, gpu_skipped_tiles, gpu_skip_reason, gpu_batches,
gpu_batch_tiles, gpu_submit_batches, gpu_readback_batches,
gpu_uploaded_bytes, gpu_readback_bytes, gpu_prepare_ms, gpu_max_in_flight,
gpu_queue_wait_ms, gpu_submit_workers, gpu_worker_threads, gpu_buffer_reuses,
gpu_buffer_allocations, gpu_staging_reuses, and
gpu_staging_allocations for tuning. CPU feeding diagnostics are split into
world_load_ms, db_read_ms, decode_ms, region_copy_ms, and
world_worker_threads, which helps distinguish a slow shader from an idle GPU
waiting for LevelDB/decode/bake work.
Environment overrides remain supported:
BEDROCK_RENDER_GPU=auto|on|off|requiredBEDROCK_RENDER_GPU_BACKEND=auto|wgpuBEDROCK_RENDER_GPU_LOG=off|summary|verbose
SurfaceRenderOptions::block_boundaries controls the default top-down 2D block
outline and height-contact shadow. It is part of the render cache signature and
is disabled when height_shading is disabled.
Streaming complete events include RenderPipelineStats, so UI status bars can
show resolved_backend, gpu_fallback_reason, cache hits/misses, worker count,
world/decode worker count, GPU batch/readback counts, and CPU/GPU timing without
waiting for a separate export summary.
CPU-only consumers can disable default features and enable the formats they need.