@@ -387,13 +398,16 @@
Scene and objects
properties: { "minecraft:bundle/has_selected_item": true },
itemReferences: { "minecraft:bundle/selected_item": apple } // AssetKey of the item drawn inside
});
-
Mobs with keyframe animations (warden, frog, camel, breeze, armadillo, sniffer, bat and others) expose them through Entities.getAnimations. The entity owns no clock, so advance it from a frame callback.
+
Mobs with keyframe animations (warden, frog, camel, breeze, armadillo, sniffer, bat and others) expose them through Entities.getAnimations. The entity owns no clock, so advance it from a frame callback. playAnimations plays several clips on one clock and adds their weighted offsets.
const animations = await Entities.getAnimations(key); // undefined without any
warden.playAnimation(animations!.roar, { loop: true, speed: 1 });
const stop = renderer.onFrame(({ delta }) => warden.advanceAnimation(delta));
warden.setAnimationTime(1.5); // or pose at an explicit time
-warden.stopAnimation(); // restores the default pose
-
GUIs take ordered texture, item and text layers in GUI pixels, with y growing down. Item layers draw stack counts and durability bars from their context; set decorations: false to hide both. gui.bounds reports the drawn area for fitting an orthographic camera, GuiHelper.inventorySlot turns a slot index into a position, and GuiHelper.recipe lays out a crafting recipe, including the result count. Text layers draw bitmap fonts from the resource pack, and GuiHelper.container, bossBar, book and tooltip return ready layer lists.
+warden.stopAnimation(); // restores the default pose
+
+warden.playAnimations([animations!.roar, animations!.sniff], { weights: [1, 0.5] });
+warden.setAnimationWeights([1, 0.25]); // without restarting playback
+
GUIs take ordered texture, item and text layers in GUI pixels, with y growing down. Item layers draw stack counts and durability bars from their context; set decorations: false to hide both. gui.bounds reports the drawn area for fitting an orthographic camera, GuiHelper.inventorySlot turns a slot index into a position, and GuiHelper.recipe lays out a crafting recipe, including the result count. Text layers draw the resource pack's bitmap and Unihex fonts, and GuiHelper.container, bossBar, book and tooltip return ready layer lists.
const gui = await scene.addGui([
{ texture: "minecraft:gui/container/generic_54", crop: [0, 0, 176, 222] },
{ item: "minecraft:item/apple", position: GuiHelper.inventorySlot(0, [8, 18]), context: { count: 16 } },
@@ -450,14 +464,14 @@ Assets and versions
Worlds and files
- MineRenderWorld stores blocks in 16³ chunks with signed coordinates and keeps faces against opaque neighbors from being drawn. With sectionMeshing, block models of any shape, animated textures, and fluid surfaces are merged into solid, translucent, and fluid meshes per section; block entities stay individual objects.
+ MineRenderWorld stores blocks in 16³ chunks with signed coordinates. Faces against opaque neighbors are not drawn, nor are faces between touching glass, ice or connected panes, as in vanilla. With sectionMeshing, block models of any shape, animated textures, and fluid surfaces are merged into solid, translucent, and fluid meshes per section; block entities stay individual objects.
import { AnvilParser, AnvilWorldSource, MineRenderWorld, NBTHelper, SchematicParser, StructureParser, WorldStreamer } from "minerender";
const world = new MineRenderWorld(renderer.scene, { sectionMeshing: true });
// Blocks from code
await world.setBlockAt(0, 0, 0, { type: "minecraft:stone" });
-await world.setBlockAt(0, 1, 0, { type: "minecraft:oak_fence", state: { north: "true" } });
+await world.setBlockAt(0, 1, 0, { type: "minecraft:oak_fence", properties: { north: "true" } });
// Vanilla structure files and legacy schematics
const nbt = await NBTHelper.fromBuffer(bytes);
@@ -480,7 +494,22 @@ Worlds and files
await streamer.updatePosition(renderer.orbitControls!.target); // call again whenever the view moves
await streamer.dispose(); // unloads its columns
The library also loads Sponge .schem files through SpongeSchematicParser and Litematica .litematic files through LitematicaParser. Anvil loading reads numeric and paletted chunks with gzip, zlib or LZ4 compression; the optional readExternalChunk and readEntityRegion callbacks add external .mcc payloads and the separate entity region files.
- Bulk placement resolves each block state once and yields to the page every few milliseconds, and section meshes are built in a worker when your bundle keeps the package's section.worker file next to the module. Saved biomes supply grass, foliage and water colors. The world has no lighting, biome blending or level of detail.
+ Bulk placement resolves each block state once and yields to the page every few milliseconds, and section meshes are built in a worker when your bundle keeps the package's section.worker file next to the module. Saved biomes supply grass, foliage and water colors.
+ With section meshing, a world can also shade terrain from the light saved in Anvil chunks, darken corners with ambient occlusion and blend biome colors across borders. renderEntities draws supported saved mobs, and raycasts return the block or mob under the pointer. Light propagation and level of detail are not supported.
+ import { Raycaster } from "three";
+
+const world = new MineRenderWorld(renderer.scene, {
+ sectionMeshing: true,
+ savedLighting: true, // sky and block light from the save
+ ambientOcclusion: true, // corner shading next to opaque blocks
+ biomeBlendRadius: 3, // average biome colors over 3 blocks
+ renderEntities: true // supported mobs at their saved positions
+});
+
+const raycaster = new Raycaster();
+raycaster.setFromCamera(pointer, renderer.camera); // pointer in normalized device coordinates
+const block = world.raycast(raycaster); // { position, block, point, normal, distance }
+const mob = world.raycastEntities(raycaster); // { type, position, object, ... }
@@ -498,6 +527,17 @@ Exporting
glTF export needs a browser. Custom shading is not baked into the exported materials. Video recording runs in real time through MediaRecorder, keeps the canvas size at the start, fills transparent pixels with black and can be cancelled with an AbortSignal.
+
+ Embeds
+ To show a render on another page without bundling the library, use the embed page in an iframe. It takes one source: skin, block, item, entity, model, a scene link from the editor's Copy embed button, or an HTTPS src pointing to a scene document.
+ <iframe
+ src="https://beta.minerender.org/embed/?item=minecraft:diamond_sword"
+ title="Diamond sword"
+ width="320" height="320" loading="lazy"
+ style="border:0"></iframe>
+ The embed fits the scene to the iframe when no camera is given, and releases its WebGL context while scrolled out of view. The embed reference lists every URL parameter.
+
+
Lifecycle
stop() pauses the loop and start() resumes it. dispose() is final: it releases the WebGL context, the controls and owned helpers. Shared assets stay cached.
@@ -510,6 +550,15 @@ Lifecycle
shutdown();
+
+ Logging
+ The library prints only warnings and errors. Raise the level for one component while investigating a problem:
+ import { Logging } from "minerender";
+
+Logging.configure({ level: "warn", namespaces: { HostedAssetSource: "debug" } });
+ On a deployed page, set localStorage["minerender:log"] = "debug" and reload; in Node, set MINERENDER_LOG=debug. See logging for handlers and the setting format.
+
+
Node
NodeRenderer.create() opens a native WebGL 2 context without a browser DOM. renderToBuffer() draws a fresh frame and returns PNG bytes. Use Node.js 22.12 or later with working native canvas and gl dependencies; headless Linux also needs Mesa and an X server such as Xvfb. See the platform setup guide.
diff --git a/apps/site/src/examples/gui.ts b/apps/site/src/examples/gui.ts
index f84f2560..2c404128 100644
--- a/apps/site/src/examples/gui.ts
+++ b/apps/site/src/examples/gui.ts
@@ -254,7 +254,7 @@ const LAYOUTS: Record Promise
const layouts: Example = {
id: "gui-layouts",
title: "Tooltips, boss bars and books",
- description: "GuiHelper builds the layer lists for common screens from the active resource pack: tooltips sized around bitmap text, boss bars, book pages with arrows, and container backgrounds with their slot layout.",
+ description: "GuiHelper builds the layer lists for common screens from the active resource pack: tooltips sized around their text, boss bars, book pages with arrows, and container backgrounds with their slot layout.",
renderer: GUI_RENDERER,
placeholder: "/placeholder-block.png",
async setup(context) {
@@ -306,11 +306,11 @@ await renderer.scene.addGui([{ text: [{ text: "Bold", bold: true }, { text: " an
export const guis: ExampleGroup = {
id: "guis",
title: "GUIs",
- lead: "Inventory screens, HUD elements, tooltips and crafting recipes built from texture crops, bitmap text and item models, rendered flat with an orthographic camera.",
+ lead: "Inventory screens, HUD elements, tooltips and crafting recipes built from texture crops, bitmap and Unihex text and item models, rendered flat with an orthographic camera.",
playgrounds: [{ url: "https://beta.minerender.org/demo/gui/", label: "GUI playground" }],
examples: [chest, hotbar, recipe, layouts],
notes: [
"Item layers draw stack counts and durability bars from their context; durability falls back to the selected version's vanilla value. Set decorations to false to hide both.",
- "Text uses the resource pack's bitmap fonts. Unihex and TrueType providers, translations and right-to-left shaping are not supported; missing glyphs draw as boxes."
+ "Text uses the resource pack's bitmap and Unihex fonts. TrueType providers, translations and right-to-left shaping are not supported; missing glyphs draw as boxes."
]
};
diff --git a/apps/site/src/icons.ts b/apps/site/src/icons.ts
index 5073eff1..5a807aa6 100644
--- a/apps/site/src/icons.ts
+++ b/apps/site/src/icons.ts
@@ -142,6 +142,16 @@ const ICONS: Record = {
".k....k.",
".kkkkkk."
],
+ embed: [
+ "........",
+ "..k..k..",
+ ".k....k.",
+ "k..gg..k",
+ "k..gg..k",
+ ".k....k.",
+ "..k..k..",
+ "........"
+ ],
entity: [
"........",
".gggggg.",