sg.js API Reference

Complete reference for the SiliconGhetto engine JavaScript API (sg.js).

import sg from 'https://cdn.siliconghetto.com/engine/v0.1/sg.js';

Lifecycle

sg.init(canvasId, width, height) — async

Initialize the engine. Loads the WASM module, selects hardware WebGPU by default, falls back to WebGL2 only when needed, and sets up the rendering context.

await sg.init('game-canvas', 800, 600);

sg.run({ update, draw })

Start the game loop. update() runs on the engine tick for game logic. draw() runs after for rendering.

sg.run({
    update() { /* game logic */ },
    draw() { /* rendering */ },
});

sg.stop()

Stop the game loop.

sg.clear(r, g, b)

Set the background clear color. Call at the start of draw().

sg.clear(0.1, 0.1, 0.2); // dark blue

Time

PropertyTypeDescription
sg.dtnumberDelta time in seconds since last frame
sg.elapsednumberTotal elapsed time in seconds
sg.framenumberTotal frame count

Input

Keyboard

MethodReturnsDescription
sg.keyDown(key)booleanKey is currently held
sg.keyPressed(key)booleanKey was pressed this frame

Key names use KeyboardEvent.code values: 'KeyW', 'ArrowUp', 'Space', 'ShiftLeft', etc.

if (sg.keyDown('KeyW')) { /* moving forward */ }
if (sg.keyPressed('Space')) { /* just jumped */ }

Mouse

Property/MethodTypeDescription
sg.mouseXnumberMouse X position on canvas
sg.mouseYnumberMouse Y position on canvas
sg.mouseDXnumberMouse X movement delta (works under pointer lock)
sg.mouseDYnumberMouse Y movement delta
sg.scrollDeltanumberScroll wheel delta (positive = down)
sg.mouseButton(btn)booleanMouse button held (0=left, 1=middle, 2=right)
sg.lockPointer()voidRequest pointer lock for FPS-style mouse look
sg.pointerLockedbooleanWhether pointer is currently locked

Entities (2D)

sg.spawn(opts)number

Create an entity. Returns a numeric handle used to reference the entity in all other calls.

const player = sg.spawn({
    x: 400, y: 300,
    sprite: { w: 32, h: 32, r: 1, g: 0.3, b: 0.3 },
    collision: { w: 32, h: 32 },
    tag: 'player',
});
OptionTypeDescription
x, ynumberInitial position
sprite{ w, h, r?, g?, b?, a? }Size and color
collision{ w, h }Collision box dimensions
tagstringTag for finding entities later
texturestringTexture ID (loaded with loadTexture)

sg.despawn(entity)

Remove an entity and clean up all subsystem state (health, physics, AI, animation).

Position & Velocity

MethodDescription
sg.setPos(e, x, y)Set 2D position
sg.setPos3D(e, x, y, z)Set 3D position
sg.getX(e)Get X position
sg.getY(e)Get Y position
sg.setVelocity(e, vx, vy)Set velocity
sg.getVelocity(e)Get velocity → { vx, vy }

Appearance

MethodDescription
sg.setSprite(e, w, h, r, g, b, a)Set size and color
sg.setTexture(e, textureId)Set texture

Tags

MethodDescription
sg.tag(e, tag)Set a tag
sg.hasTag(e, tag)Check for tag
sg.findByTag(tag)Find first entity with tag

Camera

MethodDescription
sg.setCamera(x, y, zoom)Set 2D camera position and zoom
sg.setCamera3D(px, py, pz, tx, ty, tz)Set 3D camera (position → target)
sg.cameraFollow(entity, lerpSpeed)Camera smoothly follows an entity

Drawing

Call these inside draw(). All coordinates are screen-space pixels.

MethodDescription
sg.drawAll()Draw all entities
sg.drawRect(x, y, w, h, { r, g, b, a })Draw a filled rectangle
sg.drawCircle(x, y, radius, { r, g, b, a })Draw a filled circle
sg.drawLine(x1, y1, x2, y2, { thickness, r, g, b, a })Draw a line
sg.drawText(text, x, y, size, { r, g, b })Draw text
sg.drawSprite(textureId, x, y, w, h)Draw a textured sprite
sg.drawRect(10, 10, 200, 30, { r: 0, g: 0, b: 0, a: 0.5 });
sg.drawText('Score: 100', 15, 15, 14, { r: 1, g: 1, b: 1 });

Screen

PropertyTypeDescription
sg.screenWidthnumberCanvas width in pixels
sg.screenHeightnumberCanvas height in pixels
MethodDescription
sg.resize(width, height)Resize canvas and GPU surfaces

Physics (2D)

Collision Detection

MethodReturnsDescription
sg.checkCollision(a, b)booleanAABB overlap test between two entities
sg.overlapping(e)number[]All entities overlapping with e
sg.moveAndCollide(e, dx, dy)booleanMove entity, stop at collisions

Platformer Physics

Full platformer controller with gravity, jumping (coyote time + jump buffer), and variable jump height.

const player = sg.spawn({ x: 100, y: 100, collision: { w: 16, h: 24 } });
sg.setPlatformerPhysics(player, {
    gravity: 980, jumpForce: 400, maxFall: 600, speed: 200,
    coyoteTime: 0.1, jumpBufferTime: 0.1,
});

// In update():
const input = sg.keyDown('ArrowRight') ? 1 : sg.keyDown('ArrowLeft') ? -1 : 0;
if (sg.keyPressed('Space')) sg.platformerJump(player);
sg.platformerJumpHeld(player, sg.keyDown('Space'));

const { dx, dy } = sg.updatePlatformer(player, input);
const { hitX, hitY } = sg.tilemapCollide(sg.getX(player), sg.getY(player), 8, 12, dx, dy);
sg.platformerResolve(player, hitX, hitY, dy > 0);
MethodDescription
sg.setPlatformerPhysics(e, opts)Enable platformer physics (gravity, jumpForce, maxFall, speed, coyoteTime, jumpBufferTime)
sg.updatePlatformer(e, inputX)Compute movement delta → { dx, dy }
sg.platformerJump(e)Request jump (buffered)
sg.platformerJumpHeld(e, held)Set jump button hold state
sg.platformerResolve(e, hitX, hitY, wasMovingDown)Resolve collision
sg.onGround(e)boolean — is entity on ground?
sg.facing(e)-1 or 1 — facing direction
sg.onWallLeft(e)boolean — touching wall on left
sg.onWallRight(e)boolean — touching wall on right

Top-Down Physics

sg.setTopDownPhysics(entity, { speed: 150, friction: 600 });

Tile Maps

Grid-based level system with collision.

sg.createTileMap(20, 15, 32); // 20x15 grid, 32px tiles
sg.setTile(5, 14, 1);         // solid ground
sg.setTileFlags(3, 10, 2, 2); // platform (one-way)

// In draw():
sg.drawTileMap();
MethodDescription
sg.createTileMap(w, h, tileSize)Create grid
sg.setTile(x, y, type)Set tile (0=empty)
sg.setTileFlags(x, y, type, flags)Set tile with collision flags (1=solid, 2=platform, 4=ladder, 8=hazard)
sg.getTile(x, y)Get tile type
sg.getTileFlags(x, y)Get collision flags
sg.drawTileMap()Render the map
sg.tilemapCollide(cx, cy, halfW, halfH, dx, dy)AABB collision → { x, y, hitX, hitY }
sg.tileAtWorld(wx, wy)Get tile at world position
sg.isTileHazard(x, y)Check hazard flag
sg.isTileLadder(x, y)Check ladder flag
sg.clearTileMap()Destroy tile map

Animation

Frame-based sprite animation system.

sg.addAnimation(player, 'run', { frames: [0, 1, 2, 3], fps: 10, loop: true });
sg.addAnimation(player, 'idle', { frames: [0], fps: 1 });
sg.playAnim(player, 'run');

// In draw():
const frame = sg.getAnimFrame(player); // current frame index
MethodDescription
sg.addAnimation(e, name, { frames, fps, loop })Define animation clip
sg.playAnim(e, name)Play animation
sg.getAnimFrame(e)Current frame index (-1 if none)
sg.animationName(e)Currently playing animation name
sg.animationFinished(e)Has non-looping animation finished?

Health & Damage

sg.setHealth(enemy, 50);        // 50 HP
sg.damage(enemy, 20);           // -20 HP, triggers invincibility
sg.heal(enemy, 10);             // +10 HP (capped at max)

if (sg.isDead(enemy)) sg.despawn(enemy);
MethodReturnsDescription
sg.setHealth(e, max)Set max HP (also sets current to max)
sg.damage(e, amount)booleanDeal damage (false if invincible)
sg.heal(e, amount)Restore HP
sg.getHealth(e)numberCurrent HP (-1 if no health component)
sg.getMaxHealth(e)numberMax HP
sg.isDead(e)booleanHP <= 0
sg.healthFraction(e)numberHP / maxHP (0.0 to 1.0)
sg.healthVisible(e)booleanVisible during hit flicker
sg.updateHealth()Update invincibility timers (call in update())
sg.revive(e)Reset HP to max
sg.setInvincibilityDuration(e, secs)Set i-frame duration

Projectiles

const bullet = sg.spawnProjectile(x, y, 1, 0, 300, {
    damage: 25, lifetime: 2, owner: player,
    w: 8, h: 4, r: 1, g: 0.8, b: 0,
});

// In update():
sg.updateProjectiles();
for (const { handle, damage } of sg.checkProjectileHits()) {
    sg.damage(handle, damage);
}

// In draw():
sg.drawProjectiles();
MethodDescription
sg.spawnProjectile(x, y, dirX, dirY, speed, opts)Spawn projectile → ID
sg.updateProjectiles()Move all projectiles (call in update())
sg.drawProjectiles()Render all projectiles (call in draw())
sg.checkProjectileHits()Check hits → [{ handle, damage }]
sg.projectileCountActive projectile count
sg.clearProjectiles()Remove all projectiles

AI Behaviors

sg.setAI(enemy, 'chase', { target: player, speed: 80 });
sg.setAI(guard, 'patrol', { points: [[100,200], [300,200]], speed: 60 });
sg.setAI(rabbit, 'flee', { target: player, speed: 120, maxDistance: 200 });

// In update():
for (const { handle, dx, dy, facing } of sg.updateAI()) {
    const { hitX, hitY } = sg.tilemapCollide(sg.getX(handle), sg.getY(handle), 8, 12, dx, dy);
    sg.setPos(handle, sg.getX(handle) + (hitX ? 0 : dx), sg.getY(handle) + (hitY ? 0 : dy));
}
BehaviorOptionsDescription
'chase'{ target, speed }Move toward target entity
'patrol'{ points, speed }Walk between waypoints
'flee'{ target, speed, maxDistance }Run away from target

2D Spatial Index

Fast broadphase queries for busy 2D games with many actors, pickups, hitboxes, or sensors.

const spatial = sg.createSpatialIndex({ cellSize: 64 });

spatial.insert({ entity: player, x: sg.getX(player), y: sg.getY(player), w: 18, h: 28 });
for (const enemy of enemies) {
    spatial.insert({ entity: enemy, x: sg.getX(enemy), y: sg.getY(enemy), w: 24, h: 24 });
}

const nearby = spatial.queryRadius(sg.getX(player), sg.getY(player), 160);
const hit = spatial.raycast(sg.getX(player), sg.getY(player), sg.mouseX, sg.mouseY, [player]);
for (const { a, b } of spatial.pairs()) {
    // Run exact gameplay collision only for nearby overlapping candidates.
}
MethodDescription
sg.createSpatialIndex({ cellSize })Create a reusable 2D broadphase grid
spatial.insert({ entity, x, y, w, h })Insert or replace an object’s bounds
spatial.remove(entity)Remove an object by ID
spatial.queryRect(x, y, w, h)Return items intersecting a rectangle
spatial.queryRadius(x, y, radius)Return entities within a radius, sorted nearest first
spatial.nearest(x, y, radius)Return nearest entity ID, or 0
spatial.pairs()Return unique overlapping broadphase pairs
spatial.get(entity)Return the indexed item, or undefined
spatial.raycast(x0, y0, x1, y1, ignore)Return the first bounds hit along a line segment
spatial.sweepAabb(x, y, w, h, dx, dy, ignore)Sweep a moving box and return the first hit
spatial.clear()Remove all indexed items

Kinematic Controller

const solids = sg.createSpatialIndex({ cellSize: 64 });
const playerBody = sg.createKinematicController2D({
    entity: player,
    spatial: solids,
    x: sg.getX(player),
    y: sg.getY(player),
    w: 18,
    h: 28,
});

const move = playerBody.move(inputX * speed * sg.dt, velocityY * sg.dt);
sg.setPos(player, move.x, move.y);
if (move.grounded) velocityY = 0;
MethodDescription
sg.createKinematicController2D(opts)Create a swept 2D controller backed by a spatial index
body.move(dx, dy, ignore)Move with swept collision, sliding, and contact flags
body.snapDown(distance, ignore)Stick to nearby ground after movement
body.teleport(x, y)Set position immediately
body.sync()Reinsert the current body bounds into the spatial index

Platform Composition

sg.createGame(opts) — async

Primary entry point for new games. It composes runtime options, world setup, content packs, and capability declarations.

const game = await sg.createGame({
    runtime: {
        tickRate: 60,
        deterministic: true,
        saveProfile: 'sg.save.v2',
    },
    world: {
        canvas: 'game-canvas',
        topology: 'chunked-grid-3d',
        streaming: 'player-centric',
        seed: 42,
    },
    packs: ['sg.survival@0.1.0'],
    capabilities: ['inventory', 'crafting', 'procedural_world'],
});

sg.registeredPacks()

Returns first-party pack metadata for composition tooling:

const [{ id, version, capabilities }] = sg.registeredPacks();
OptionDefaultDescription
runtime.tickRate60Deterministic simulation tick rate
runtime.deterministictrueUse deterministic runtime assumptions
runtime.saveProfile'sg.save.v2'Save/migration profile identifier
world.topology'chunked-grid-3d'World topology
world.streaming'player-centric'Chunk streaming strategy
packs[]Registered content packs, either strings like 'sg.survival@0.1.0' or { id, version } objects. Use sg.registeredPacks() to inspect first-party IDs and versions. Omitting the version uses the registered first-party version. Unknown pack IDs or unsupported versions throw during composition.
capabilities[]Requested platform capabilities

Returns { seed, canvas, width, height, runtime, world, packs, capabilities, composition, template, game }. composition.bootMode is 'base-runtime' for a base world and 'pack-template' when a first-party pack boots through a pack template.

Block Worlds

Quick Start

const { seed } = await sg.createGame({
    world: {
        canvas: 'game-canvas',
        worldHeight: 64,
        seed: 42,
    },
});

sg.run({
    update() { sg.fpsUpdate(); },
    draw() { sg.clear(0.5, 0.7, 1.0); },
});

sg.createGame(opts) — async

Platform setup: initializes engine, creates a voxel world, generates biome-driven terrain, enables FPS controller, and sets up pointer lock.

OptionDefaultDescription
canvas'game-canvas'Canvas element ID
width960Canvas width
height600Canvas height
world.worldHeight64Y height
seedrandomTerrain generation seed
player{}FPS controller settings (see below)
biomesdefaultsCustom biome array (replaces defaults)
spawncenter[x, y, z] spawn position

Returns { seed, canvas, width, height }.

Block Operations

MethodDescription
sg.createVoxelWorld(sx, sy, sz)Create empty voxel world
sg.setBlock(x, y, z, type)Set a block (auto-remeshes chunk)
sg.getBlock(x, y, z)Get block type at position
sg.fillBlocks(x1, y1, z1, x2, y2, z2, type)Fill region with block type
sg.voxelSizeX/Y/ZWorld dimensions

Block Types

Access via sg.BLOCKS or sg.blockTypes:

sg.setBlock(x, y, z, sg.BLOCKS.STONE);
sg.setBlock(x, y, z, sg.BLOCKS.DIAMOND_ORE);
IDConstantIDConstant
0AIR22CALCITE
1DIRT23FLOWER_YELLOW
2GRASS24FLOWER_RED
3STONE25TALL_GRASS
4SAND26DEAD_BUSH
5WOOD27CACTUS
6LEAVES28MUSHROOM_RED
7WATER29MUSHROOM_BROWN
8BRICK30CHERRY_LEAVES
9COBBLESTONE31BIRCH_WOOD
10PLANKS32SPRUCE_WOOD
11SNOW33JUNGLE_WOOD
12GRAVEL34ACACIA_WOOD
13PACKED_ICE35GLOW_LICHEN
14SANDSTONE36IRON_ORE
15RED_SAND37GOLD_ORE
16TERRACOTTA38DIAMOND_ORE
17PODZOL39COAL_ORE
18MYCELIUM40LAVA
19MUD41DRY_GRASS
20CLAY42SPRUCE_LEAVES
21MOSSY_STONE

Block names are available via sg.BLOCK_NAMES[id].

FPS Controller

Enabled automatically by createGame(), or manually:

sg.enableFPSController({
    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
    playerRadius: 0.28,   // collision cylinder radius
    playerHeight: 1.65,   // collision cylinder height
});

Built-in controls: WASD (move), Mouse (look), Space (jump), Shift (sprint), F (fly toggle), Ctrl (fly down).

MethodReturnsDescription
sg.fpsUpdate(){ x, y, z, eyeY, targetX/Y/Z, onGround, flyMode, sprinting }Update controller (call in update())
sg.fpsSetPosition(x, y, z)Teleport player
sg.fpsGetPosition(){ x, y, z }Player feet position
sg.fpsGetLook(){ yaw, pitch }Camera angles (radians)
sg.fpsSetFly(bool)Set fly mode

Raycasting

DDA (Digital Differential Analyzer) — exact, never misses a block.

// From FPS eye position:
const hit = sg.voxelRaycast(7);
if (hit.hit) {
    // hit.x, hit.y, hit.z — the block that was hit
    // hit.prevX, hit.prevY, hit.prevZ — the air block before it (for placing)
    // hit.blockType — block type ID
}

// From arbitrary position + direction:
const hit2 = sg.voxelRaycastFrom(ox, oy, oz, dx, dy, dz, 20);

Collision

MethodReturnsDescription
sg.voxelCollide(px, py, pz, dx, dy, dz, radius, height){ x, y, z, hitY }AABB collision (standalone)
sg.voxelFindSpawnY(x, z)numberHighest solid block + 2 at column
sg.voxelIsWater(x, y, z)booleanIs block water?

Terrain Generation

sg.generateTerrain({ seed: 42 });

Generates terrain using simplex noise with biome-driven terrain, cave systems, Y-level ore distribution, biome-specific trees, and surface decoration.

Biome System

Default biomes are registered automatically. To customize:

// Replace all biomes with custom set:
sg.resetBiomes();
sg.addBiome({
    name: 'Alien Desert',
    tempRange: [0.5, 1.0],
    moistRange: [-1, 0],
    surface: sg.BLOCKS.RED_SAND,
    subSurface: sg.BLOCKS.TERRACOTTA,
    treeDensity: 0.02,
    treeTrunk: sg.BLOCKS.CACTUS,
    treeLeaves: sg.BLOCKS.AIR,
});
sg.generateTerrain({ seed: 42 });
MethodDescription
sg.addBiome(opts)Add a biome (first match wins)
sg.resetBiomes()Clear all biomes (for custom set)
sg.clearBiomes()Reset to 20 defaults
sg.biomeCountNumber of registered biomes

Assets

await sg.loadTexture('hero', 'hero.png');
await sg.loadSound('jump', 'jump.wav');

sg.drawSprite('hero', 100, 200, 32, 32);
sg.playSound('jump');
MethodDescription
sg.loadTexture(id, url)Load texture (async)
sg.loadSound(id, url)Load audio (async)
sg.playSound(id)Play sound effect
sg.playMusic(id)Play looping music
sg.stopMusic()Stop music
sg.setVolume(v)Set master volume (0.0–1.0)

CDN Library

await sg.loadTexture('hero', sg.lib.texture('hero-spritesheet'));
await sg.loadSound('jump', sg.lib.sound('jump'));

Particles

const emitter = sg.createEmitter(400, 300);
sg.emitBurst(emitter, 50); // spawn 50 particles

3D Meshes

const cube = sg.createCube();
const sphere = sg.createSphere();
const plane = sg.createPlane();