Voxel Game Guide
Build a Minecraft-style 3D sandbox game with the SiliconGhetto engine. The engine handles world generation, meshing, rendering, physics, and FPS controls — you write the game logic.
Minimal Voxel Game (15 lines)
import sg from 'https://cdn.siliconghetto.com/engine/v0.1/sg.js';
await sg.createVoxelGame({ canvas: 'game-canvas', seed: 42 });
sg.run({
update() { sg.fpsUpdate(); },
draw() {
sg.clear(0.5, 0.7, 1.0);
const cx = 480, cy = 300;
sg.drawRect(cx - 1, cy - 8, 2, 16, { r: 1, g: 1, b: 1, a: 0.7 });
sg.drawRect(cx - 8, cy - 1, 16, 2, { r: 1, g: 1, b: 1, a: 0.7 });
},
});
That gives you: 20-biome terrain, FPS movement (WASD + mouse), jump, sprint, fly mode, and a crosshair.
createVoxelGame Options
await sg.createVoxelGame({
canvas: 'game-canvas', // canvas element ID
width: 960, height: 600, // canvas size
worldSize: [256, 64, 256],// world dimensions [x, y, z]
seed: 42, // terrain seed (random if omitted)
player: {
speed: 7, // walk speed
jumpForce: 8.5, // jump velocity
gravity: 22, // gravity strength
sensitivity: 0.003, // mouse look sensitivity
flySpeed: 14, // fly mode speed
sprintMultiplier: 1.6,// shift sprint multiplier
},
});
Block Interaction
Break and place blocks with raycasting:
document.getElementById('game-canvas').addEventListener('mousedown', e => {
if (!sg.pointerLocked) return;
const hit = sg.voxelRaycast(7); // 7 block reach
if (!hit.hit) return;
if (e.button === 0) {
// Left click: break block
sg.setBlock(hit.x, hit.y, hit.z, sg.BLOCKS.AIR);
} else if (e.button === 2) {
// Right click: place block
sg.setBlock(hit.prevX, hit.prevY, hit.prevZ, sg.BLOCKS.STONE);
}
});
The prevX/Y/Z is the air block the ray passed through before hitting the solid — that’s where the placed block goes.
Block Types
43 block types available via sg.BLOCKS:
Terrain: DIRT, GRASS, STONE, SAND, GRAVEL, CLAY, MUD, SANDSTONE, RED_SAND, TERRACOTTA, CALCITE, PACKED_ICE, SNOW, DRY_GRASS, PODZOL, MYCELIUM, MOSSY_STONE
Wood: WOOD, BIRCH_WOOD, SPRUCE_WOOD, JUNGLE_WOOD, ACACIA_WOOD, PLANKS
Foliage: LEAVES, SPRUCE_LEAVES, CHERRY_LEAVES, TALL_GRASS, FLOWER_YELLOW, FLOWER_RED, DEAD_BUSH, CACTUS, MUSHROOM_RED, MUSHROOM_BROWN
Building: BRICK, COBBLESTONE
Ores: COAL_ORE, IRON_ORE, GOLD_ORE, DIAMOND_ORE
Fluids: WATER, LAVA
Special: GLOW_LICHEN, AIR
Get the display name: sg.BLOCK_NAMES[sg.BLOCKS.DIAMOND_ORE] → "Diamond Ore".
Inventory System
The engine doesn’t enforce an inventory — you implement it in JS. Here’s a simple hotbar:
const hotbar = [
{ id: sg.BLOCKS.DIRT, count: 64 },
{ id: sg.BLOCKS.STONE, count: 64 },
{ id: sg.BLOCKS.WOOD, count: 32 },
{ id: sg.BLOCKS.BRICK, count: 16 },
{ id: sg.BLOCKS.SAND, count: 32 },
];
let selected = 0;
// Select with number keys
document.addEventListener('keydown', e => {
const n = parseInt(e.key);
if (n >= 1 && n <= hotbar.length) selected = n - 1;
});
// Select with scroll wheel (in update):
if (sg.scrollDelta !== 0) {
selected = ((selected + Math.sign(sg.scrollDelta)) % hotbar.length + hotbar.length) % hotbar.length;
}
Crafting
Crafting is game logic — define recipes and check materials:
const RECIPES = [
{ in: [sg.BLOCKS.WOOD, sg.BLOCKS.WOOD], out: sg.BLOCKS.PLANKS, count: 4 },
{ in: [sg.BLOCKS.STONE, sg.BLOCKS.STONE], out: sg.BLOCKS.COBBLESTONE, count: 4 },
];
function craft(recipe) {
const a = hotbar.find(s => s.id === recipe.in[0] && s.count > 0);
const b = hotbar.find(s => s.id === recipe.in[1] && s.count > 0);
if (a && b) {
a.count--; b.count--;
addToHotbar(recipe.out, recipe.count);
}
}
Custom Biomes
Override the 20 defaults with your own:
sg.resetBiomes(); // clear all defaults
sg.addBiome({
name: 'Alien Desert',
tempRange: [-1, 1], // match everything
moistRange: [-1, 0], // dry side
surface: sg.BLOCKS.RED_SAND,
subSurface: sg.BLOCKS.TERRACOTTA,
treeDensity: 0.02,
treeTrunk: sg.BLOCKS.CACTUS,
treeLeaves: sg.BLOCKS.AIR,
});
sg.addBiome({
name: 'Crystal Forest',
tempRange: [-1, 1],
moistRange: [0, 1], // wet side
surface: sg.BLOCKS.MYCELIUM,
subSurface: sg.BLOCKS.STONE,
treeDensity: 0.15,
treeTrunk: sg.BLOCKS.BIRCH_WOOD,
treeLeaves: sg.BLOCKS.CHERRY_LEAVES,
});
await sg.createVoxelGame({ canvas: 'game-canvas' });
// Biomes are applied during terrain generation
Biomes are matched by temperature and moisture noise at each terrain column. First match wins.
Day/Night Cycle
The engine uses a fixed sun direction — but you can simulate day/night with sky color:
let timeOfDay = 0.35; // 0=midnight, 0.5=noon
// In update():
timeOfDay = (timeOfDay + sg.dt / 180) % 1.0; // 3-minute cycle
// In draw():
const sun = Math.sin(timeOfDay * Math.PI * 2);
const day = Math.max(sun, 0);
sg.clear(0.1 + 0.45 * day, 0.1 + 0.6 * day, 0.18 + 0.72 * day);
Water Detection
Check if the player is swimming:
const pos = sg.fpsGetPosition();
if (sg.voxelIsWater(Math.floor(pos.x), Math.floor(pos.y), Math.floor(pos.z))) {
// Blue overlay
sg.drawRect(0, 0, 960, 600, { r: 0.05, g: 0.15, b: 0.45, a: 0.3 });
}
The FPS controller automatically slows movement and applies swim physics in water.
Default Biomes
The engine ships with 20 biomes:
| Biome | Surface | Trees |
|---|---|---|
| Plains | Grass | Sparse oak |
| Forest | Grass | Dense oak |
| Birch Forest | Grass | Birch (white bark) |
| Dark Forest | Grass | Dense, tall oak |
| Taiga | Podzol | Spruce (conical) |
| Snowy Plains | Snow | Sparse spruce |
| Ice Spikes | Packed Ice | None |
| Desert | Sand | Cactus |
| Badlands | Red Sand | None |
| Savanna | Dry Grass | Acacia (flat-top) |
| Jungle | Grass | Huge jungle trees |
| Swamp | Mud | Short oak |
| Mushroom Fields | Mycelium | Giant mushrooms |
| Mountains | Stone | Sparse spruce |
| Stony Peaks | Calcite | None |
| Meadow | Grass | Very sparse |
| Cherry Grove | Grass | Cherry (pink leaves) |
| Mangrove Swamp | Mud | Mangrove |
| Flower Forest | Grass | Oak + birch |
| Frozen Ocean | Packed Ice | None |
Performance Tips
- World size: 256x64x256 runs well. 512x64x512 is the practical maximum for the current engine.
- Block updates:
setBlock()triggers chunk remeshing. Batch changes withfillBlocks()when possible. - Fly mode: Press F to fly — useful for testing and seeing your world from above.