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:

BiomeSurfaceTrees
PlainsGrassSparse oak
ForestGrassDense oak
Birch ForestGrassBirch (white bark)
Dark ForestGrassDense, tall oak
TaigaPodzolSpruce (conical)
Snowy PlainsSnowSparse spruce
Ice SpikesPacked IceNone
DesertSandCactus
BadlandsRed SandNone
SavannaDry GrassAcacia (flat-top)
JungleGrassHuge jungle trees
SwampMudShort oak
Mushroom FieldsMyceliumGiant mushrooms
MountainsStoneSparse spruce
Stony PeaksCalciteNone
MeadowGrassVery sparse
Cherry GroveGrassCherry (pink leaves)
Mangrove SwampMudMangrove
Flower ForestGrassOak + birch
Frozen OceanPacked IceNone

Performance Tips

  • World size: 256x64x256 runs well. 512x64x512 is the practical maximum for the current engine.
  • Block updates: setBlock() triggers chunk remeshing. Batch changes with fillBlocks() when possible.
  • Fly mode: Press F to fly — useful for testing and seeing your world from above.