blockymodel-prefab
v0.1.1
Published
Render Hytale prefab files with Three.js
Maintainers
Readme
blockymodel-prefab
Render Hytale prefab files (.prefab.json) with Three.js.
Installation
npm install blockymodel-prefab threeQuick Start
import * as THREE from "three";
import { PrefabLoader, PrefabRenderer, StaticRegistry } from "blockymodel-prefab";
// Setup Three.js scene
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
// Create asset registry (static for offline, or ApiRegistry for server-backed)
const registry = new StaticRegistry();
// Create prefab renderer
const prefabRenderer = new PrefabRenderer(scene, registry);
// Load and render a prefab file
const fileInput = document.querySelector<HTMLInputElement>("#prefab-file");
fileInput?.addEventListener("change", async (e) => {
const file = (e.target as HTMLInputElement).files?.[0];
if (file) {
await prefabRenderer.loadAndRender(file);
prefabRenderer.centerCamera(camera);
}
});Features
- Fast instanced rendering: Uses
THREE.InstancedMeshfor efficient rendering of large prefabs (80k+ blocks) - Flexible asset registry: Support for API-backed or static registries
- Block type filtering: Show/hide specific block types
- Progress callbacks: Track loading progress for large prefabs
API
PrefabLoader
Parse and analyze prefab files.
import { PrefabLoader } from "blockymodel-prefab";
// Load from file
const prefab = await PrefabLoader.loadFromFile(file);
// Load from URL
const prefab = await PrefabLoader.loadFromUrl("/prefabs/spawn.prefab.json");
// Parse JSON string
const prefab = PrefabLoader.parse(jsonString);
// Get bounds
const bounds = PrefabLoader.getBounds(prefab);
console.log(`Size: ${bounds.width}x${bounds.height}x${bounds.depth}`);
// Get unique block types
const types = PrefabLoader.getUniqueBlockNames(prefab);PrefabRenderer
Main renderer for prefab files.
import { PrefabRenderer, StaticRegistry } from "blockymodel-prefab";
const registry = new StaticRegistry();
const renderer = new PrefabRenderer(scene, registry, {
debug: true,
onProgress: (loaded, total) => {
console.log(`Loading: ${loaded}/${total} block types`);
},
});
// Render prefab
await renderer.render(prefab);
// Get stats
const stats = renderer.getStats();
console.log(`Rendered ${stats.totalBlocks} blocks in ${stats.meshes} meshes`);
// Toggle block type visibility
renderer.setBlockTypeVisible("Soil_Grass", false);
// Clean up
renderer.dispose();Asset Registries
StaticRegistry
Offline registry with fallback texture generation and multi-texture support.
import { StaticRegistry, createDefaultStaticRegistry } from "blockymodel-prefab";
// Create with default terrain blocks
const registry = createDefaultStaticRegistry("https://s3.hytalegarage.com/hytale-assets");
// Or create empty and register blocks manually
const registry = new StaticRegistry();
// Single texture block
registry.register({
name: "Rock_Stone",
blockType: "cube",
textureUrl: "https://example.com/stone.png",
});
// Multi-texture block (different textures per face)
registry.register({
name: "Soil_Grass",
blockType: "cube",
textureTop: "https://example.com/grass_top.png",
textureSides: "https://example.com/grass_side.png",
textureBottom: "https://example.com/dirt.png",
});Multi-Texture Blocks
Blocks like grass, snow-covered soil, and mycelium have different textures per face. The renderer automatically detects and applies multi-texture materials:
interface BlockAsset {
name: string;
blockType: "cube";
// Single texture (all faces)
textureUrl?: string;
// Multi-texture (per-face)
textureTop?: string; // +Y face
textureBottom?: string; // -Y face
textureSides?: string; // +X, -X, +Z, -Z faces
}The StaticRegistry.generateFallback() method automatically generates multi-texture paths for known block types:
Soil_Grass*- Grass top, grass side, dirt bottomSoil_Snow*- Snow top, snow side, dirt bottomSoil_Mycelium*- Mycelium texturesSoil_Podzol*- Podzol textures
ApiRegistry
Server-backed registry with caching.
import { ApiRegistry } from "blockymodel-prefab";
const registry = new ApiRegistry("https://api.hytalegarage.com", {
enableCache: true,
});
// Check availability
if (await registry.isAvailable()) {
const block = await registry.getBlock("Soil_Grass");
}Prefab Format
interface Prefab {
version: number; // Format version (e.g., 8)
blockIdVersion: number; // Block ID version (e.g., 11)
anchorX: number; // Origin offset
anchorY: number;
anchorZ: number;
blocks: {
x: number; // Position
y: number;
z: number;
name: string; // Block type (e.g., "Soil_Grass")
rotation?: 0|1|2|3; // Optional 90° rotation
}[];
}Three.js Face Order
For multi-texture blocks, materials are applied in Three.js BoxGeometry face order:
| Index | Direction | Face | |-------|-----------|---------| | 0 | +X | Right | | 1 | -X | Left | | 2 | +Y | Top | | 3 | -Y | Bottom | | 4 | +Z | Front | | 5 | -Z | Back |
Performance
The renderer uses instanced meshes for optimal GPU performance:
| Prefab Size | Block Types | Draw Calls | Render Time | |-------------|-------------|------------|-------------| | 10,000 | 20 | 20 | ~50ms | | 50,000 | 40 | 40 | ~150ms | | 100,000 | 50 | 50 | ~300ms |
Dependencies
three(peer dependency) - 3D rendering
License
MIT
