Render Hytale prefab files with Three.js
npm install blockymodel-prefabRender Hytale prefab files (.prefab.json) with Three.js.
``bash`
npm install blockymodel-prefab three
`typescript
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
fileInput?.addEventListener("change", async (e) => {
const file = (e.target as HTMLInputElement).files?.[0];
if (file) {
await prefabRenderer.loadAndRender(file);
prefabRenderer.centerCamera(camera);
}
});
`
- Fast instanced rendering: Uses THREE.InstancedMesh for 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
Parse and analyze prefab files.
`typescript
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);
`
Main renderer for prefab files.
`typescript
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();
`
#### StaticRegistry
Offline registry with fallback texture generation and multi-texture support.
`typescript
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",
});
`
Blocks like grass, snow-covered soil, and mycelium have different textures per face. The renderer automatically detects and applies multi-texture materials:
`typescript
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.
`typescript
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");
}
`
`typescript`
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
}[];
}
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 |
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 |
- three` (peer dependency) - 3D rendering
MIT