
Building Router
- 52 installs
- 8 repo stars
- Updated August 4, 2026
- bbeierle12/skill-mcp-claude
Building-router is a Claude skill that classifies a Three.js building-game project and routes it to 9 specialized implementation skills.
About
Building-router is a Claude skill that routes 3D building-game mechanics work in Three.js to 9 specialized skills. It is the entry point for survival games, sandbox builders, and base builders, classifying a project by scale and features then matching it to performance, physics, multiplayer, terrain, decay, UX, and platform skills. A developer starts here for any building-mechanics project.
- Router that dispatches to 9 specialized Three.js building-game skills
- Signal-matching table for performance, physics, and multiplayer needs
- Notes most games need 3-5 skills combined
Building Router by the numbers
- 52 all-time installs (skills.sh)
- Ranked #160 of 247 Game Development skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
building-router capabilities & compatibility
- Capabilities
- skill routing · project classification
- Use cases
- orchestration
What building-router says it does
Router for 3D building game mechanics in Three.js.
**Combine** — Most games need 3-5 skills together
npx skills add https://github.com/bbeierle12/skill-mcp-claude --skill building-routerAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 52 |
|---|---|
| repo stars | ★ 8 |
| Last updated | August 4, 2026 |
| Repository | bbeierle12/skill-mcp-claude ↗ |
What it does
Choose which of 9 Three.js building-game skills to load for a given project.
Who is it for?
Deciding which building-mechanics skills to combine for a game project.
Skip if: Non-game or single-concern tasks that need one specific skill directly.
When should I use this skill?
Creating survival games, sandbox builders, base builders, or any game with player-constructed structures.
What you get
The right combination of specialized building-mechanics skills selected for the project.
- Selected skill set for a building-game project
By the numbers
- routes to 9 specialized skills
- most games need 3-5 skills together
- 4-step routing protocol
Files
Building Mechanics Router
Routes to 9 specialized skills based on game requirements.
Routing Protocol
1. Classify — Single/multiplayer + scale + core features 2. Match — Apply signal matching rules below 3. Combine — Most games need 3-5 skills together 4. Load — Read matched SKILL.md files before implementation
Quick Route
Tier 1: Core Mechanics
| Need | Skill | Signals |
|---|---|---|
| Spatial queries, collision | performance-at-scale | slow, lag, optimize, spatial, collision, thousands |
| Stability, damage, collapse | structural-physics | stability, collapse, support, damage, Fortnite, Rust, Valheim |
| Network sync, prediction | multiplayer-building | network, multiplayer, sync, server, latency, authoritative |
Tier 2: Enhanced Features
| Need | Skill | Signals |
|---|---|---|
| Slopes, foundations, anchoring | terrain-integration | slope, terrain, foundation, ground, pillar, heightmap |
| Timer decay, Tool Cupboard | decay-upkeep | decay, upkeep, maintenance, tool cupboard, abandoned |
| Blueprints, undo/redo, preview | builder-ux | blueprint, prefab, undo, redo, ghost, preview, selection |
Tier 3: Platform & Reference
| Need | Skill | Signals |
|---|---|---|
| Touch, VR, accessibility | platform-building | mobile, touch, VR, hand tracking, colorblind |
| Design analysis, trade-offs | case-studies-reference | how does Fortnite/Rust do, compare games, trade-offs |
Signal Priority
When multiple signals present: 1. Multiplayer explicit → multiplayer-building required 2. Scale indicator → >1000 pieces triggers performance-at-scale 3. Persistence → Long-running servers trigger decay-upkeep 4. Platform constraint → Mobile/VR triggers platform-building 5. Default → structural-physics always relevant for building games
Common Combinations
Full Survival (Rust-style, 6 skills)
performance-at-scale → spatial indexing
structural-physics → stability + damage
multiplayer-building → networking
terrain-integration → foundations on slopes
decay-upkeep → Tool Cupboard + upkeep
builder-ux → blueprints + undoBattle Royale Building (2 skills)
performance-at-scale → fast collision
multiplayer-building → low-latency syncSingle-Player Builder (3-4 skills)
structural-physics → stability + damage
terrain-integration → natural terrain
builder-ux → blueprints + undo
performance-at-scale → if >1000 piecesPersistent Server (4 skills)
multiplayer-building → networking
structural-physics → stability
decay-upkeep → automatic cleanup
performance-at-scale → entity managementDecision Table
| Mode | Scale | Terrain | Skills |
|---|---|---|---|
| Single | <1K | Grid | physics + ux |
| Single | <1K | Natural | physics + terrain + ux |
| Single | >1K | Any | performance + physics + ux |
| Multi | Fast | Any | performance + multiplayer |
| Multi | Survival | Any | performance + physics + multiplayer + decay |
| Multi | Persistent | Any | performance + physics + multiplayer + decay + ux |
Integration Order
When combining skills, wire in this sequence: 1. Spatial index → Query foundation for all other systems 2. Validator → Uses spatial for neighbor/support detection 3. Damage → Uses spatial for cascade radius 4. Network → Broadcasts all state changes 5. Client prediction → Uses local spatial + validator
Fallback
- No scale stated → Ask: "How many pieces expected?"
- Unclear mode → Ask: "Single-player or multiplayer?"
- Generic "building game" → Start with
structural-physics+builder-ux
Reference
See references/integration-guide.md for complete wiring patterns and code examples.
{
"name": "building-router",
"description": "Routes to 9 specialized building game skills based on game type, scale, and core features including physics, multiplayer sync, and terrain manipulation.",
"tags": [
"building-game",
"3d",
"routing"
],
"sub_skills": [
{
"name": "performance",
"file": "references/performance.md",
"triggers": [
"optimization",
"LOD",
"culling",
"instancing",
"batching"
]
},
{
"name": "physics",
"file": "references/physics.md",
"triggers": [
"collision",
"structural integrity",
"gravity",
"rigidbody"
]
},
{
"name": "multiplayer",
"file": "references/multiplayer.md",
"triggers": [
"sync",
"netcode",
"replication",
"server authority"
]
},
{
"name": "terrain",
"file": "references/terrain.md",
"triggers": [
"voxel",
"terrain",
"procedural",
"chunk"
]
}
],
"source": "claude-user",
"type": "router",
"depends_on": [
"performance-at-scale",
"structural-physics",
"multiplayer-building",
"terrain-integration",
"decay-upkeep",
"builder-ux",
"platform-building",
"case-studies-reference"
],
"enhances": [],
"last_reviewed_at": "2026-05-27",
"review_score": 69,
"relevance_tier": "C"
}
Integration Guide
Detailed patterns for combining the 3 building mechanics skills.
Architecture Overview
┌─────────────────────────────────────────────────────────────┐
│ Building System │
├─────────────────────────────────────────────────────────────┤
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ Performance │ │ Structural │ │ Multiplayer │ │
│ │ at Scale │◄─┤ Physics │◄─┤ Building │ │
│ └─────────────┘ └─────────────┘ └─────────────────────┘ │
│ │ │ │ │
│ Spatial Index Validation + Network + │
│ + Streaming Damage Prediction │
└─────────────────────────────────────────────────────────────┘Data flows right-to-left: Network events trigger physics, physics uses spatial queries.
Full Integration Example
Setup
import * as THREE from 'three';
// Performance
import { SpatialHashGrid } from 'performance-at-scale/scripts/spatial-hash-grid.js';
import { Octree } from 'performance-at-scale/scripts/octree.js';
import { ChunkManager } from 'performance-at-scale/scripts/chunk-manager.js';
// Physics
import { HeuristicValidator } from 'structural-physics/scripts/heuristic-validator.js';
import { StabilityOptimizer } from 'structural-physics/scripts/stability-optimizer.js';
import { DamageSystem } from 'structural-physics/scripts/damage-propagation.js';
// Networking
import { BuildingNetworkServer, BuildingNetworkClient } from 'multiplayer-building/scripts/building-network-manager.js';
import { ClientPrediction } from 'multiplayer-building/scripts/client-prediction.js';Initialization Order
Order matters. Initialize bottom-up (dependencies first):
class IntegratedBuildingSystem {
constructor(options = {}) {
// 1. Spatial indexing (no dependencies)
this.spatial = new SpatialHashGrid(options.cellSize ?? 10);
// 2. Validator (uses spatial for neighbor queries)
this.validator = new HeuristicValidator({
mode: options.physicsMode ?? 'heuristic',
findNeighbors: (pos, radius) => this.spatial.queryRadius(pos, radius)
});
// 3. Optimizer (wraps validator)
this.optimizer = new StabilityOptimizer(this.validator, {
maxCacheSize: 10000,
updateBudgetMs: 2
});
// 4. Damage system (uses validator + spatial)
this.damage = new DamageSystem(this.validator, {
findNeighbors: (pos, radius) => this.spatial.queryRadius(pos, radius)
});
// 5. Network (uses everything above)
if (options.multiplayer) {
this.initNetworking(options);
}
// Wire events
this.wireEvents();
}
initNetworking(options) {
if (options.isServer) {
this.network = new BuildingNetworkServer(this, {
tickRate: options.tickRate ?? 20
});
} else {
this.network = new BuildingNetworkClient(this);
this.prediction = new ClientPrediction(this);
}
}
wireEvents() {
// Damage triggers network broadcast
this.damage.onPieceDestroyed = (piece, cascade) => {
if (this.network?.broadcastPieceDestroyed) {
this.network.broadcastPieceDestroyed(piece.id, cascade);
}
};
// Stability changes trigger optimizer
this.validator.onStabilityChanged = (piece, stability) => {
this.optimizer.queueUpdate(piece.id, 'high');
};
}
}Piece Lifecycle
// PLACEMENT
placePiece(type, position, rotation) {
// 1. Create piece
const piece = this.createPiece(type, position, rotation);
// 2. Add to spatial index
this.spatial.insert(piece, position);
// 3. Register with validator
this.validator.addPiece(piece);
// 4. Queue stability calculation
this.optimizer.onPiecePlaced(piece);
// 5. Network sync (if multiplayer)
if (this.network) {
this.network.broadcastPiecePlaced(piece);
}
return piece;
}
// DESTRUCTION
destroyPiece(piece) {
// 1. Apply destruction through damage system (handles cascade)
const destroyed = this.damage.destroyPiece(piece);
// 2. Remove each from spatial index
for (const p of destroyed) {
this.spatial.remove(p);
}
// 3. Validator removal handled by damage system
// 4. Network broadcast handled by wired event
return destroyed;
}
// DAMAGE
applyDamage(piece, amount, type = 'physical') {
// Damage system handles everything
this.damage.applyDamage(piece, amount, type);
}Common Patterns
Pattern: Spatial Query for Physics
Physics often needs "nearby pieces" for support detection or cascade damage.
// BAD: Physics recalculates neighbors every time
validator.findSupports = (piece) => {
return allPieces.filter(p => p.position.distanceTo(piece.position) < 5);
}; // O(n) every query
// GOOD: Physics uses spatial index
validator.findSupports = (piece) => {
return spatial.queryRadius(piece.position, 5);
}; // O(1) averagePattern: Network Uses Validation
Server validates placement before accepting.
// Server-side
handlePlaceRequest(clientId, request) {
const position = request.position;
// 1. Check spatial collision
const collisions = this.spatial.queryRadius(position, 0.5);
if (collisions.length > 0) {
return reject('Position occupied');
}
// 2. Check structural validity
const validation = this.validator.validatePlacement({
type: request.pieceType,
position
});
if (!validation.valid) {
return reject(validation.reason);
}
// 3. Actually place
const piece = this.placePiece(request.pieceType, position, request.rotation);
return confirm(piece.id);
}Pattern: Client Prediction with Local Validation
Client predicts using local copies of spatial + validator.
// Client-side
predictPlace(type, position, rotation) {
// 1. Local collision check
const collisions = this.spatial.queryRadius(position, 0.5);
if (collisions.length > 0) {
showError('Position occupied');
return null;
}
// 2. Local stability check
const validation = this.validator.validatePlacement({ type, position });
if (!validation.valid) {
showError(validation.reason);
return null;
}
// 3. Create predicted piece
const predicted = this.prediction.predictPlace(type, position, rotation);
// 4. Add to local spatial (for subsequent predictions)
this.spatial.insert(predicted, position);
return predicted;
}
// On server rejection
onPredictionRejected(tempId, reason) {
const piece = this.prediction.getPredicted(tempId);
if (piece) {
this.spatial.remove(piece); // Rollback spatial
}
}Pattern: Chunked World with Per-Chunk Systems
For very large worlds, each chunk has its own spatial index.
class ChunkedBuildingSystem {
constructor() {
this.chunkManager = new ChunkManager({
chunkSize: 256,
loadRadius: 2,
onChunkLoad: (chunk) => this.initChunkSystems(chunk),
onChunkUnload: (chunk) => this.cleanupChunkSystems(chunk)
});
this.chunkSpatials = new Map();
this.chunkValidators = new Map();
}
initChunkSystems(chunk) {
const spatial = new SpatialHashGrid(10);
const validator = new HeuristicValidator({
findNeighbors: (pos, r) => spatial.queryRadius(pos, r)
});
// Load existing pieces
for (const piece of chunk.pieces) {
spatial.insert(piece, piece.position);
validator.addPiece(piece);
}
this.chunkSpatials.set(chunk.id, spatial);
this.chunkValidators.set(chunk.id, validator);
}
getSystemsForPosition(position) {
const chunkId = this.chunkManager.getChunkId(position);
return {
spatial: this.chunkSpatials.get(chunkId),
validator: this.chunkValidators.get(chunkId)
};
}
}Performance Budgets
Recommended per-frame budgets for 60fps (16.6ms total):
| System | Budget | Notes |
|---|---|---|
| Spatial queries | 1ms | Usually instant |
| Stability updates | 2ms | Batched by optimizer |
| Damage processing | 1ms | Spread cascades over frames |
| Network send | 1ms | Batched deltas |
| Network receive | 2ms | Apply deltas |
| Total building | 7ms | Leaves 9ms for rendering/other |
Troubleshooting
Pieces falling through supports
- Check validator mode matches game style
- Verify findNeighbors returns correct pieces
- Check support detection tolerance
Network desync
- Ensure server is authoritative
- Check delta acknowledgment flow
- Verify prediction rollback works
Performance drops with many pieces
- Profile with performance-profiler.js
- Check spatial cell size matches piece density
- Enable stability optimizer caching
Cascade damage too slow
- Spread destructions over frames (damage system does this)
- Reduce cascade radius
- Use spatial query for neighbors, not full scan
Multiplayer Building
Server Authority
All building operations should be server-authoritative:
// Client requests build
[Command]
void CmdRequestBuild(int pieceId, Vector3 position, Quaternion rotation)
{
// Server validates
if (!CanPlace(position, rotation, pieceId))
{
TargetBuildFailed(connectionToClient, "Invalid placement");
return;
}
if (!HasResources(connectionToClient.identity, pieceId))
{
TargetBuildFailed(connectionToClient, "Insufficient resources");
return;
}
// Server spawns and syncs to all clients
GameObject piece = Instantiate(piecePrefabs[pieceId], position, rotation);
NetworkServer.Spawn(piece);
// Deduct resources
DeductResources(connectionToClient.identity, pieceId);
}State Synchronization
Delta Compression
public class BuildingState : NetworkBehaviour
{
SyncList<BuildingPieceData> pieces = new SyncList<BuildingPieceData>();
public struct BuildingPieceData
{
public uint id;
public ushort prefabIndex;
public Vector3 position;
public Quaternion rotation;
public float integrity;
}
void OnPiecesChanged(SyncList<BuildingPieceData>.Operation op, int index, BuildingPieceData oldItem, BuildingPieceData newItem)
{
switch (op)
{
case SyncList<BuildingPieceData>.Operation.OP_ADD:
SpawnPieceLocally(newItem);
break;
case SyncList<BuildingPieceData>.Operation.OP_REMOVEAT:
DestroyPieceLocally(oldItem.id);
break;
case SyncList<BuildingPieceData>.Operation.OP_SET:
UpdatePieceLocally(newItem);
break;
}
}
}Interest Management
Only sync buildings in player's area:
public class BuildingInterestManagement : InterestManagement
{
public float visibilityRange = 100f;
public override bool OnCheckObserver(NetworkIdentity identity, NetworkConnectionToClient conn)
{
Vector3 playerPos = conn.identity.transform.position;
Vector3 buildingPos = identity.transform.position;
return Vector3.Distance(playerPos, buildingPos) <= visibilityRange;
}
}Prediction & Rollback
Client-Side Prediction
[Client]
void TryBuild(int pieceId, Vector3 position, Quaternion rotation)
{
// Predict locally
GameObject preview = Instantiate(ghostPrefabs[pieceId], position, rotation);
preview.GetComponent<GhostPiece>().SetPending();
pendingBuilds.Add(new PendingBuild {
localId = nextLocalId++,
preview = preview,
pieceId = pieceId,
position = position,
rotation = rotation,
timestamp = Time.time
});
// Send to server
CmdRequestBuild(pieceId, position, rotation, pendingBuilds.Count - 1);
}
[TargetRpc]
void TargetBuildConfirmed(NetworkConnection conn, int localId, uint serverId)
{
var pending = pendingBuilds.Find(p => p.localId == localId);
if (pending != null)
{
pending.preview.GetComponent<GhostPiece>().Confirm();
pendingBuilds.Remove(pending);
}
}
[TargetRpc]
void TargetBuildFailed(NetworkConnection conn, int localId, string reason)
{
var pending = pendingBuilds.Find(p => p.localId == localId);
if (pending != null)
{
Destroy(pending.preview);
pendingBuilds.Remove(pending);
ShowError(reason);
}
}Bandwidth Optimization
- Quantize positions (use shorts instead of floats)
- Batch multiple operations per frame
- Use bit flags for piece properties
- Compress rotation to smallest-three format
Building Performance
Draw Call Optimization
GPU Instancing
// Unity - Instance rendering for repeated objects
MaterialPropertyBlock props = new MaterialPropertyBlock();
Graphics.DrawMeshInstanced(mesh, 0, material, matrices, count, props);Static Batching
Combine static geometry at build time:
// Unity
StaticBatchingUtility.Combine(buildingRoot);Dynamic Batching
For small meshes (<300 verts), ensure:
- Same material
- No scaling differences
- No runtime mesh modifications
Level of Detail (LOD)
// LOD Group setup
LODGroup lodGroup = building.AddComponent<LODGroup>();
LOD[] lods = new LOD[3];
lods[0] = new LOD(0.6f, highDetailRenderers); // 60%+ screen
lods[1] = new LOD(0.3f, mediumDetailRenderers); // 30-60% screen
lods[2] = new LOD(0.1f, lowDetailRenderers); // 10-30% screen
lodGroup.SetLODs(lods);Occlusion Culling
Frustum Culling
Automatic in most engines - ensure bounds are correct.
Portal Culling
For indoor environments:
// Define rooms and portals
OcclusionPortal portal = doorway.AddComponent<OcclusionPortal>();
portal.open = doorIsOpen;Chunk-Based Loading
public class ChunkManager : MonoBehaviour
{
const int CHUNK_SIZE = 16;
const int VIEW_DISTANCE = 4;
Dictionary<Vector2Int, Chunk> loadedChunks = new();
void Update()
{
Vector2Int playerChunk = WorldToChunk(player.position);
// Load nearby chunks
for (int x = -VIEW_DISTANCE; x <= VIEW_DISTANCE; x++)
{
for (int z = -VIEW_DISTANCE; z <= VIEW_DISTANCE; z++)
{
Vector2Int coord = playerChunk + new Vector2Int(x, z);
if (!loadedChunks.ContainsKey(coord))
{
LoadChunkAsync(coord);
}
}
}
// Unload distant chunks
UnloadDistantChunks(playerChunk, VIEW_DISTANCE + 2);
}
}Mesh Merging
Combine multiple building pieces into single meshes:
public Mesh CombineMeshes(List<MeshFilter> filters)
{
CombineInstance[] combine = new CombineInstance[filters.Count];
for (int i = 0; i < filters.Count; i++)
{
combine[i].mesh = filters[i].sharedMesh;
combine[i].transform = filters[i].transform.localToWorldMatrix;
}
Mesh combinedMesh = new Mesh();
combinedMesh.CombineMeshes(combine, true, true);
return combinedMesh;
}Memory Management
- Pool building piece prefabs
- Use shared materials
- Compress textures (BC7/ASTC)
- Stream meshes for large structures
Building Physics
Structural Integrity
Support Propagation
public class StructuralIntegrity : MonoBehaviour
{
public float maxIntegrity = 100f;
public float currentIntegrity;
public bool isFoundation;
HashSet<StructuralIntegrity> supporters = new();
HashSet<StructuralIntegrity> supported = new();
public void RecalculateIntegrity()
{
if (isFoundation)
{
currentIntegrity = maxIntegrity;
return;
}
float bestSupport = 0f;
foreach (var supporter in supporters)
{
float propagated = supporter.currentIntegrity * GetConnectionStrength(supporter);
bestSupport = Mathf.Max(bestSupport, propagated);
}
currentIntegrity = bestSupport;
// Collapse if no support
if (currentIntegrity <= 0)
{
Collapse();
}
// Propagate to supported pieces
foreach (var piece in supported)
{
piece.RecalculateIntegrity();
}
}
float GetConnectionStrength(StructuralIntegrity supporter)
{
// Vertical connections stronger than horizontal
float verticalBonus = supporter.transform.position.y < transform.position.y ? 0.95f : 0.7f;
return verticalBonus;
}
}Damage Propagation
public void TakeDamage(float damage)
{
currentIntegrity -= damage;
if (currentIntegrity <= 0)
{
Collapse();
}
else
{
// Recalculate connected pieces
foreach (var piece in supported)
{
piece.RecalculateIntegrity();
}
}
}Collision Detection
Overlap Testing for Placement
public bool CanPlace(Vector3 position, Quaternion rotation, BuildingPiece piece)
{
Collider[] overlaps = Physics.OverlapBox(
position + piece.bounds.center,
piece.bounds.extents,
rotation,
buildingLayer
);
// Filter out valid snap connections
foreach (var overlap in overlaps)
{
if (!IsValidSnapPoint(overlap, piece))
{
return false;
}
}
return true;
}Snap Point System
public class SnapPoint : MonoBehaviour
{
public SnapType type; // Floor, Wall, Ceiling, Foundation
public bool isOccupied;
public SnapPoint connectedTo;
public bool CanSnapTo(SnapPoint other)
{
if (isOccupied || other.isOccupied) return false;
// Check compatible types
return AreTypesCompatible(type, other.type);
}
public void SnapTo(SnapPoint other)
{
isOccupied = true;
other.isOccupied = true;
connectedTo = other;
other.connectedTo = this;
// Update structural connections
GetComponent<StructuralIntegrity>().AddSupporter(
other.GetComponent<StructuralIntegrity>()
);
}
}Destruction Physics
Ragdoll on Collapse
public void Collapse()
{
// Convert to physics object
Rigidbody rb = gameObject.AddComponent<Rigidbody>();
rb.mass = CalculateMass();
rb.AddExplosionForce(500f, transform.position + Random.insideUnitSphere, 5f);
// Disconnect from structure
foreach (var supporter in supporters)
{
supporter.supported.Remove(this);
}
foreach (var piece in supported)
{
piece.supporters.Remove(this);
piece.RecalculateIntegrity();
}
// Destroy after falling
Destroy(gameObject, 5f);
}Performance Tips
- Use compound colliders, not mesh colliders
- Batch physics queries
- Use layers to filter collision checks
- Sleep rigidbodies when stable
Terrain Systems
Voxel Architecture
Chunk Structure
public class VoxelChunk
{
public const int SIZE = 16;
// Flat array for cache efficiency
byte[] voxels = new byte[SIZE * SIZE * SIZE];
public byte GetVoxel(int x, int y, int z)
{
return voxels[x + y * SIZE + z * SIZE * SIZE];
}
public void SetVoxel(int x, int y, int z, byte type)
{
voxels[x + y * SIZE + z * SIZE * SIZE] = type;
isDirty = true;
}
}Chunk Management
public class ChunkManager
{
Dictionary<Vector3Int, VoxelChunk> chunks = new();
Queue<Vector3Int> meshQueue = new();
public void ModifyTerrain(Vector3 worldPos, byte voxelType)
{
Vector3Int chunkCoord = WorldToChunk(worldPos);
Vector3Int localPos = WorldToLocal(worldPos);
if (!chunks.TryGetValue(chunkCoord, out var chunk))
{
chunk = LoadOrGenerateChunk(chunkCoord);
}
chunk.SetVoxel(localPos.x, localPos.y, localPos.z, voxelType);
// Queue mesh rebuild
if (!meshQueue.Contains(chunkCoord))
{
meshQueue.Enqueue(chunkCoord);
}
// Also update adjacent chunks if on boundary
UpdateAdjacentChunks(chunkCoord, localPos);
}
}Mesh Generation
Greedy Meshing
public Mesh GenerateGreedyMesh(VoxelChunk chunk)
{
List<Vector3> vertices = new();
List<int> triangles = new();
List<Vector2> uvs = new();
// Process each axis
for (int axis = 0; axis < 3; axis++)
{
int u = (axis + 1) % 3;
int v = (axis + 2) % 3;
int[] x = new int[3];
int[] q = new int[3];
q[axis] = 1;
// Sweep through the volume
for (x[axis] = -1; x[axis] < VoxelChunk.SIZE;)
{
// Compute mask
bool[,] mask = ComputeMask(chunk, axis, x, u, v);
x[axis]++;
// Generate quads from mask using greedy algorithm
GenerateQuadsFromMask(mask, axis, x, u, v, vertices, triangles, uvs);
}
}
Mesh mesh = new Mesh();
mesh.vertices = vertices.ToArray();
mesh.triangles = triangles.ToArray();
mesh.uv = uvs.ToArray();
mesh.RecalculateNormals();
return mesh;
}Procedural Generation
Noise-Based Terrain
public byte GenerateVoxel(Vector3 worldPos)
{
float height = GetTerrainHeight(worldPos.x, worldPos.z);
if (worldPos.y > height)
{
return AIR;
}
else if (worldPos.y > height - 1)
{
return GRASS;
}
else if (worldPos.y > height - 4)
{
return DIRT;
}
else
{
return STONE;
}
}
float GetTerrainHeight(float x, float z)
{
float scale = 0.01f;
// Layer multiple octaves
float height = 0;
height += Mathf.PerlinNoise(x * scale, z * scale) * 32;
height += Mathf.PerlinNoise(x * scale * 2, z * scale * 2) * 16;
height += Mathf.PerlinNoise(x * scale * 4, z * scale * 4) * 8;
return height + 64; // Base height
}Cave Generation
bool IsCave(Vector3 pos)
{
float scale = 0.05f;
float threshold = 0.6f;
// 3D noise for caves
float noise = Perlin3D(pos.x * scale, pos.y * scale, pos.z * scale);
return noise > threshold;
}Serialization
Chunk Save/Load
public byte[] SerializeChunk(VoxelChunk chunk)
{
using var ms = new MemoryStream();
using var writer = new BinaryWriter(ms);
// Run-length encoding
byte currentType = chunk.voxels[0];
int count = 1;
for (int i = 1; i < chunk.voxels.Length; i++)
{
if (chunk.voxels[i] == currentType && count < 255)
{
count++;
}
else
{
writer.Write(currentType);
writer.Write((byte)count);
currentType = chunk.voxels[i];
count = 1;
}
}
writer.Write(currentType);
writer.Write((byte)count);
return ms.ToArray();
}Performance Tips
- Generate meshes on background threads
- Use object pooling for chunk GameObjects
- Implement chunk LOD for distant terrain
- Cache neighbor chunk references
Related skills
FAQ
How many skills does it route to?
Nine specialized skills across performance, physics, multiplayer, terrain, decay, UX, and platform support.
How many skills does a typical game need?
Most games need 3-5 skills together.