Complete API reference and guide for using Nucleation in Python.
pip install nucleationfrom nucleation import Schematic
# Create schematic
schematic = Schematic("my_schematic")
schematic.set_block(0, 0, 0, "minecraft:stone")
# Save to file (auto-detects format from extension)
schematic.save("output.litematic")- Installation
- Core API
- Loading and Saving
- Block Operations
- Region Operations
- Block Entities
- SchematicBuilder
- Simulation
- Procedural Building
- 3D Mesh Generation
pip install nucleationgit clone https://github.com/Schem-at/Nucleation
cd Nucleation
maturin develop --features pythonMain class for working with schematics.
class Schematic:
def __init__(self, name: str):
"""Create empty schematic"""
# Loading/Saving
def load_from_bytes(self, data: bytes) -> None:
"""Load from bytes (auto-detects format)"""
def load_from_litematic(self, data: bytes) -> None:
"""Load from litematic format"""
def load_from_schematic(self, data: bytes) -> None:
"""Load from WorldEdit schematic format"""
def to_litematic(self) -> bytes:
"""Save as litematic format"""
def to_schematic(self) -> bytes:
"""Save as WorldEdit schematic format"""
def to_snapshot(self) -> bytes:
"""Fast binary snapshot (for worker transfer, caching)"""
def from_snapshot(self, data: bytes) -> None:
"""Load from snapshot format"""
def save(self, path: str, format: str = "auto",
version: str = None, settings: str = None) -> None:
"""Save to file (auto-detects format from extension)"""
# Format Support
@staticmethod
def get_supported_import_formats() -> list[str]:
"""List supported import formats"""
@staticmethod
def get_supported_export_formats() -> list[str]:
"""List supported export formats"""
@staticmethod
def get_format_versions(format: str) -> list[str]:
"""Get available versions for an export format"""
@staticmethod
def get_default_format_version(format: str) -> str | None:
"""Get default version for an export format"""
# Block operations
def set_block(self, x: int, y: int, z: int, block_name: str) -> None:
"""Set block at position"""
def set_block_with_properties(self, x: int, y: int, z: int,
block_name: str, properties: dict) -> None:
"""Set block with properties"""
def set_block_from_string(self, x: int, y: int, z: int,
block_string: str) -> None:
"""Set block from bracket notation string"""
def get_block(self, x: int, y: int, z: int) -> str | None:
"""Get block name at position"""
def get_block_with_properties(self, x: int, y: int, z: int) -> dict | None:
"""Get block with properties"""
# Block entities
def get_block_entity(self, x: int, y: int, z: int) -> dict | None:
"""Get block entity at position"""
def get_all_block_entities(self) -> list[dict]:
"""Get all block entities"""
# Region operations
def copy_region(self, source_region: str,
min_x: int, min_y: int, min_z: int,
max_x: int, max_y: int, max_z: int,
target_x: int, target_y: int, target_z: int,
excluded_blocks: list[str]) -> None:
"""Copy region to new position"""
# Information
def get_dimensions(self) -> tuple[int, int, int]:
"""Get schematic dimensions (width, height, depth)"""
def get_block_count(self) -> int:
"""Get number of non-air blocks"""
def get_volume(self) -> int:
"""Get total volume"""
def get_region_names(self) -> list[str]:
"""Get all region names"""
def get_info(self) -> str:
"""Get debug information"""
def print_schematic(self) -> str:
"""Get ASCII representation"""
# Iteration
def blocks(self) -> list[dict]:
"""Get all blocks with positions and properties"""
def chunks(self, width: int, height: int, length: int) -> list[dict]:
"""Get chunks (bottom-up order)"""
def chunks_with_strategy(self, width: int, height: int, length: int,
strategy: str, cx: int = 0, cy: int = 0, cz: int = 0) -> list[dict]:
"""Get chunks with ordering strategy"""
def get_chunk_blocks(self, offset_x: int, offset_y: int, offset_z: int,
width: int, height: int, length: int) -> list[dict]:
"""Get blocks in specific chunk"""
# Simulation (requires simulation feature)
def create_simulation_world(self) -> SimulationWorld:
"""Create simulation world"""
def create_simulation_world_with_options(self, options: SimulationOptions) -> SimulationWorld:
"""Create simulation world with custom options"""Represents a block with properties.
class BlockState:
def __init__(self, name: str):
"""Create block state"""
def with_property(self, key: str, value: str) -> None:
"""Add property (mutates in place)"""
@property
def name(self) -> str:
"""Get block name"""
@property
def properties(self) -> dict[str, str]:
"""Get all properties"""from nucleation import Schematic
# Load litematic
with open("input.litematic", "rb") as f:
data = f.read()
schematic = Schematic("loaded")
schematic.load_from_litematic(data)
# Auto-detect format
schematic.load_from_bytes(data)
# Check supported formats
print(Schematic.get_supported_import_formats())
# ['litematic', 'schematic', 'mcstructure']
print(schematic.get_dimensions())# One-liner save (auto-detects format from extension)
schematic.save("output.litematic")
schematic.save("output.schem")
# Save with explicit format and version
schematic.save("output.schem", format="schematic", version="v2")
# Or get bytes directly
litematic_bytes = schematic.to_litematic()
schem_bytes = schematic.to_schematic()
# Check export formats and versions
print(Schematic.get_supported_export_formats())
# ['litematic', 'schematic', 'mcstructure', 'snapshot']
print(Schematic.get_format_versions("schematic"))
# ['v1', 'v2', 'v3']
print(Schematic.get_default_format_version("schematic"))
# 'v3'The snapshot format (.nusn) is a fast binary serialization designed for caching and worker transfer. It's much faster than standard formats but not compatible with Minecraft.
# Serialize to snapshot bytes
snapshot_data = schematic.to_snapshot()
# Load from snapshot
schematic2 = Schematic("restored")
schematic2.from_snapshot(snapshot_data)
# Save/load via file
schematic.save("cache.nusn") # auto-detects snapshot from .nusn extension# Simple block
schematic.set_block(0, 0, 0, "minecraft:stone")
# Block with properties (dict)
schematic.set_block_with_properties(0, 1, 0, "minecraft:lever", {
"facing": "east",
"powered": "false"
})
# Block from string (bracket notation)
schematic.set_block_from_string(
1, 1, 0,
"minecraft:redstone_wire[power=15,north=side,south=side]"
)
# Using BlockState
from nucleation import BlockState
block = BlockState("minecraft:repeater")
block.with_property("facing", "east")
block.with_property("delay", "2")
# Note: BlockState is mainly for reading, use set_block_with_properties for setting# Get block name only
block_name = schematic.get_block(0, 0, 0)
if block_name:
print(f"Block: {block_name}")
# Get block with properties
block_data = schematic.get_block_with_properties(0, 1, 0)
if block_data:
print(f"Block: {block_data['name']}")
print(f"Properties: {block_data['properties']}")# Get all blocks
all_blocks = schematic.blocks()
for block in all_blocks:
print(f"({block['x']}, {block['y']}, {block['z']}) = {block['name']}")
print(f"Properties: {block['properties']}")
# Filter non-air blocks
non_air_blocks = [b for b in all_blocks if 'air' not in b['name']]
# Count block types
from collections import Counter
block_counts = Counter(b['name'] for b in all_blocks)
for block_name, count in block_counts.most_common():
print(f"{block_name}: {count}")# Get chunks (bottom-up order)
chunks = schematic.chunks(16, 16, 16)
for chunk in chunks:
print(f"Chunk at ({chunk['offset_x']}, {chunk['offset_y']}, {chunk['offset_z']})")
print(f"Blocks: {len(chunk['blocks'])}")
# Get chunks with strategy
strategies = [
"distance_to_camera",
"top_down",
"bottom_up",
"center_outward",
"random"
]
chunks = schematic.chunks_with_strategy(
16, 16, 16,
"distance_to_camera",
0, 100, 0 # Camera position
)
# Get specific chunk
chunk_blocks = schematic.get_chunk_blocks(0, 0, 0, 16, 16, 16)# Copy a region
schematic.copy_region(
"Main", # Source region name
0, 0, 0, # Min coordinates
10, 10, 10, # Max coordinates
20, 0, 0, # Target position
["minecraft:air"] # Excluded blocks
)# Get all region names
regions = schematic.get_region_names()
print(f"Regions: {regions}")
# Get dimensions
width, height, depth = schematic.get_dimensions()
print(f"Size: {width}x{height}x{depth}")
# Get block/volume counts
print(f"Blocks: {schematic.get_block_count()}")
print(f"Volume: {schematic.get_volume()}")# Set block with entity using string notation
schematic.set_block_from_string(
0, 1, 0,
'minecraft:barrel[facing=up]{signal=13}'
)
# Note: Direct block entity manipulation is limited in Python bindings
# Use bracket notation with {nbt} for most cases# Get single block entity
entity = schematic.get_block_entity(0, 1, 0)
if entity:
print(f"Entity: {entity}")
# Entity is a dict with NBT data
# Get all block entities
all_entities = schematic.get_all_block_entities()
for entity in all_entities:
print(f"Entity at ({entity['x']}, {entity['y']}, {entity['z']}): {entity['data']}")Build schematics programmatically with ASCII art and compositional design.
See SchematicBuilder Guide for complete documentation.
from nucleation import SchematicBuilder
circuit = SchematicBuilder.new() \
.from_template("""
# Base layer
ccc
ccc
# Logic layer
─→─
│█│
""") \
.build()# Build basic gates
and_gate = create_and_gate()
xor_gate = create_xor_gate()
# Compose into larger circuit
half_adder = SchematicBuilder.new() \
.map_schematic('A', and_gate) \
.map_schematic('X', xor_gate) \
.layers([["AX"]]) \
.build()Simulate redstone circuits in real-time.
from nucleation import Schematic
schematic = Schematic("circuit")
# Build circuit...
schematic.set_block_from_string(0, 1, 0, "minecraft:lever[facing=north,powered=false]")
schematic.set_block_from_string(5, 1, 0, "minecraft:redstone_lamp[lit=false]")
# ... add redstone wiring ...
# Create simulation world
world = schematic.create_simulation_world()
# Toggle lever
world.on_use_block(0, 1, 0)
# Run simulation
world.tick(10)
world.flush()
# Check if lamp is lit
is_lit = world.is_lit(5, 1, 0)
print(f"Lamp is lit: {is_lit}")from nucleation import SimulationOptions
# Configure custom IO positions
options = SimulationOptions()
options.add_custom_io(0, 1, 0) # Input position
options.add_custom_io(10, 1, 0) # Output position
world = schematic.create_simulation_world_with_options(options)
# Inject custom signal strength (0-15)
world.set_signal_strength(0, 1, 0, 15) # Max power
world.tick(5)
world.flush()
# Read signal strength
output_signal = world.get_signal_strength(10, 1, 0)
print(f"Output signal: {output_signal}")# Set multiple signals
positions = [(0, 1, 0), (0, 1, 2), (0, 1, 4)]
strengths = [15, 0, 15]
for (x, y, z), strength in zip(positions, strengths):
world.set_signal_strength(x, y, z, strength)
world.tick(10)
world.flush()
# Read multiple signals
outputs = [world.get_signal_strength(x, y, z) for x, y, z in positions]High-level API for circuit simulation with typed inputs/outputs.
See TypedCircuitExecutor Guide for complete documentation.
from nucleation import TypedCircuitExecutor, IoType, LayoutFunction, Value
# Define IO mappings
inputs = {
"a": {
"io_type": IoType.Bool,
"layout": LayoutFunction.OneToOne,
"positions": [(0, 1, 0)]
},
"b": {
"io_type": IoType.Bool,
"layout": LayoutFunction.OneToOne,
"positions": [(0, 1, 2)]
}
}
outputs = {
"result": {
"io_type": IoType.Bool,
"layout": LayoutFunction.OneToOne,
"positions": [(10, 1, 0)]
}
}
# Create executor
executor = TypedCircuitExecutor(world, inputs, outputs)
# Execute with typed values
input_values = {
"a": Value.Bool(True),
"b": Value.Bool(True)
}
result = executor.execute(input_values, {
"mode": "fixed_ticks",
"ticks": 100
})
# Get typed output
output = result["outputs"]["result"]
print(f"Result: {output}") # Value.Bool(True)from typing import TypedDict, Literal
class BlockDict(TypedDict):
x: int
y: int
z: int
name: str
properties: dict[str, str]
class ChunkDict(TypedDict):
offset_x: int
offset_y: int
offset_z: int
blocks: list[BlockDict]
ChunkStrategy = Literal[
"distance_to_camera",
"top_down",
"bottom_up",
"center_outward",
"random"
]
class ExecutionMode(TypedDict, total=False):
mode: Literal["fixed_ticks", "until_condition", "until_stable", "until_change"]
ticks: int
output: str
condition: any
timeout: int
stable_ticks: intfrom nucleation import Schematic, load_schematic
# Load existing schematic (auto-detects format)
schematic = load_schematic("input.litematic")
# Modify blocks
for x in range(10):
for z in range(10):
schematic.set_block(x, 0, z, "minecraft:stone")
# Save modified version
schematic.save("output.litematic")from nucleation import Schematic
def build_and_test_circuit():
schematic = Schematic("test_circuit")
# Build AND gate
schematic.set_block(0, 0, 0, "minecraft:stone")
schematic.set_block_from_string(0, 1, 0, "minecraft:lever[facing=north,powered=false]")
# ... build circuit ...
# Test simulation
world = schematic.create_simulation_world()
world.on_use_block(0, 1, 0) # Toggle input
world.tick(10)
world.flush()
output = world.is_lit(10, 1, 0)
assert output == True, "Test failed!"
print("Test passed!")
build_and_test_circuit()import os
from nucleation import Schematic
def convert_all_schematics(input_dir: str, output_dir: str):
"""Convert all .schematic files to .litematic"""
os.makedirs(output_dir, exist_ok=True)
for filename in os.listdir(input_dir):
if not filename.endswith('.schematic'):
continue
input_path = os.path.join(input_dir, filename)
output_path = os.path.join(output_dir, filename.replace('.schematic', '.litematic'))
schematic = load_schematic(input_path)
schematic.save(output_path)
print(f"Converted: {filename}")
convert_all_schematics("input/", "output/")Generate structures procedurally using geometric shapes and brushes.
from nucleation import Schematic, BuildingTool, Shape, Brush
schematic = Schematic("build")
# Create a sphere shape
sphere = Shape.sphere(
0, 0, 0, # Center (x, y, z)
10.0 # Radius
)
# Create a gradient brush (Red -> Blue)
brush = Brush.linear_gradient(
0, 0, 0, 255, 0, 0, # Start: Pos(0,0,0), Red(255,0,0)
10, 0, 0, 0, 0, 255, # End: Pos(10,0,0), Blue(0,0,255)
1, # 1 = Oklab interpolation (smoother), 0 = RGB
["wool"] # Optional filter: only use wool blocks
)
# Apply brush to shape
BuildingTool.fill(schematic, sphere, brush)For simple tasks, you can use the direct methods on Schematic:
# Fill a cuboid region with a solid block
schematic.fill_cuboid(
0, 0, 0, # Min (x, y, z)
10, 5, 10, # Max (x, y, z)
"minecraft:red_concrete"
)
# Fill a sphere with a solid block
schematic.fill_sphere(
0, 0, 0, # Center (x, y, z)
10.0, # Radius
"minecraft:blue_wool"
)# Solid block
solid = Brush.solid("minecraft:stone")
# Solid color (matches closest block)
color = Brush.color(255, 128, 0, None) # Orange
# 4-Point Bilinear Gradient (Quad)
bilinear = Brush.bilinear_gradient(
0, 0, 0, 10, 0, 0, 0, 10, 0, # Origin, U-end, V-end
255, 0, 0, # Origin Color (Red)
0, 0, 255, # U-end Color (Blue)
0, 255, 0, # V-end Color (Green)
255, 255, 0, # Opposite Color (Yellow)
1, # Oklab interpolation
None # No filter
)
# Point Cloud Gradient (Arbitrary points, IDW)
points_brush = Brush.point_gradient(
[
((0, 0, 0), (255, 0, 0)),
((10, 10, 10), (0, 0, 255)),
((5, 5, 5), (0, 255, 0))
],
2.5, # Falloff (power), default 2.0
1, # Oklab
None
)The meshing feature generates 3D meshes from schematics using Minecraft resource packs.
from nucleation import ResourcePack
# From a file
pack = ResourcePack.from_file("path/to/resourcepack.zip")
# From bytes
with open("pack.zip", "rb") as f:
pack = ResourcePack.from_bytes(f.read())
# Inspect the pack
print(f"Blockstates: {pack.blockstate_count}")
print(f"Models: {pack.model_count}")
print(f"Textures: {pack.texture_count}")
print(f"Namespaces: {pack.namespaces}")from nucleation import Schematic, MeshConfig
schematic = Schematic()
schematic.from_litematic(data)
# Default config
config = MeshConfig()
# Or customize
config = MeshConfig(
cull_hidden_faces=True,
ambient_occlusion=True,
ao_intensity=0.4,
cull_occluded_blocks=True,
greedy_meshing=True, # reduces triangle count
biome="plains",
atlas_max_size=4096,
)
# Generate a GLB mesh
result = schematic.to_mesh(pack, config)
result.save("output.glb")
print(f"Vertices: {result.vertex_count}, Triangles: {result.triangle_count}")
# Generate a USDZ mesh (Apple AR format)
usdz_result = schematic.to_usdz(pack, config)
usdz_result.save("output.usdz")
# Generate raw mesh data for custom pipelines
raw = schematic.to_raw_mesh(pack, config)
positions = raw.positions_flat() # [x, y, z, x, y, z, ...]
indices = raw.indices()
atlas_pixels = raw.texture_rgba()# One mesh per region
multi = schematic.mesh_by_region(pack, config)
for name in multi.region_names:
mesh = multi.get_mesh(name)
mesh.save(f"{name}.glb")
# One mesh per 16x16x16 chunk
chunks = schematic.mesh_by_chunk(pack, config)
for coord in chunks.chunk_coordinates:
mesh = chunks.get_mesh(*coord)
# coord is (x, y, z)
# Custom chunk size
chunks = schematic.mesh_by_chunk_size(pack, 32, config)# List all entries
blockstates = pack.list_blockstates() # ["minecraft:stone", ...]
models = pack.list_models()
textures = pack.list_textures()
# Query individual entries
json_str = pack.get_blockstate_json("minecraft:stone")
model_json = pack.get_model_json("minecraft:block/stone")
info = pack.get_texture_info("minecraft:block/stone") # {width, height, is_animated, frame_count}
pixels = pack.get_texture_pixels("minecraft:block/stone") # raw RGBA bytes
# Add custom entries
pack.add_blockstate_json("custom:block", '{"variants": {"": {"model": "custom:block/my_block"}}}')
pack.add_model_json("custom:block/my_block", '{"parent": "block/cube_all", "textures": {"all": "custom:block/my_texture"}}')
pack.add_texture("custom:block/my_texture", 16, 16, rgba_bytes)