@misterscan/sesi-game
v2.0.2
Published
Optional Babylon.js and Electron desktop game runtime for Sesi
Maintainers
Readme
@misterscan/sesi-game combines Babylon.js, Havok physics, Babylon GUI, and Electron so Sesi programs can create live 3D scenes and package them as desktop applications. The large engine dependencies stay here instead of increasing the size of the core Sesi package.
Install
Install Sesi, then add the game runtime to your project:
npm install -g @misterscan/sesi
npm install @misterscan/sesi-gameThe game package does not install or bundle Sesi itself. It is resolved by Sesi when a script imports std/game.
Game development and builds require local mode because they launch Electron and access project assets:
sesi -l game.sesiQuick start
allow "std/game" in as Game
let game = Game.create({
title: "First Light",
width: 1280,
height: 720,
background: "#050816"
})
let scene = game.create_scene("main")
scene.orbit_camera("camera", {
alpha: -1.57,
beta: 1.05,
radius: 12,
target: Game.vec3(0, 1, 0)
})
scene.hemispheric_light("sky", {intensity: 0.9})
let floor = scene.ground("floor", {width: 20, height: 20})
let player = scene.sphere("player", {
diameter: 1.5,
position: Game.vec3(0, 1, 0)
})
let player_material = scene.pbr_material("player_material", {
color: Game.color("#22d3ee"),
emissive: Game.color("#164e63"),
roughness: 0.25
})
player.material = player_material
scene.enable_physics({gravity: Game.vec3(0, -9.81, 0)})
scene.add_body(floor, {type: "static", shape: "box"})
scene.add_body(player, {
type: "dynamic",
shape: "sphere",
mass: 1,
restitution: 0.5
})
game.run()Live game code
Sesi callbacks execute inside the Electron game host. Meshes, cameras, materials, GUI controls, vectors, and physics bodies are live native handles, so properties can be read and changed directly.
game.input.bind("left", ["KeyA", "ArrowLeft"])
game.input.bind("right", ["KeyD", "ArrowRight"])
fn fixed_update(_dt) {
let x = 0
if game.input.down("left") { x = x - 6 }
if game.input.down("right") { x = x + 6 }
player.set_velocity(Game.vec3(x, player.velocity().y, 0))
}
fn collided(other) {
if other != null { show "Hit" other.name }
}
game.on_fixed_update(fixed_update)
player.on_collision(collided)The scheduler provides fixed updates for deterministic movement and physics, variable updates for presentation, serialized callback execution, and a visible error overlay if a callback fails.
Assets
Register models, textures, environments, audio, and fonts before loading or playing them:
game.assets.add("ship", "model", "assets/ship.glb")
game.assets.add("metal", "texture", "assets/metal.png")
game.assets.add("impact", "audio", "assets/impact.wav")
let ship = scene.load_model("player_ship", "ship", {
position: Game.vec3(0, 1, 0)
})
scene.play_sound("impact", {volume: 0.8})Assets can also be produced by Sesi itself and then registered with the game:
allow "std/draw" in as Draw
allow "std/audio" in as Audio
make_dir("assets")
Draw.pixel_grid(["0110", "1111", "1111", "0110"], {
"0": "transparent",
"1": "#22d3ee"
}, 24)
Draw.save_png("assets/icon.png", 96, 96, "#07111f")
Audio.save("assets/pickup.wav", "E6", 90, "sine")
game.assets.add("icon", "texture", "assets/icon.png")
game.assets.add("pickup", "audio", "assets/pickup.wav")Local assets remain subject to Sesi filesystem permissions. Desktop builds download and bundle registered remote assets, package local glTF dependencies, and rewrite their references.
Scenes and engine features
- Box, sphere, plane, ground, and cylinder primitives
- Registered glTF and GLB models with animation groups
- Free, orbit, and follow cameras
- Hemispheric, directional, point, and spot lights
- Standard and PBR materials
- Havok rigid bodies, triggers, forces, impulses, raycasts, and collision callbacks
- Keyboard, pointer, wheel, pointer-lock, and gamepad input
- Numeric and vector transform animations
- Spatial and non-spatial audio
- Text, image, button, panel, and stack GUI controls
- App-scoped key/value storage
Sesi Game uses left-handed, Y-up coordinates: +X points right and +Z points forward. Distances are measured in meters and rotations in radians.
Lifecycle
Register game-wide callbacks with:
game.on_start(started)
game.on_update(update)
game.on_fixed_update(fixed_update)
game.on_stop(stopped)Scenes provide on_enter, on_exit, on_update, and on_fixed_update. Start and stop callbacks may be asynchronous; frame, input, GUI, and collision callbacks are synchronous so ticks never overlap.
Build a desktop app
game.build("build/MyGame")Builds are unsigned, unpacked applications for the current operating system and architecture. Sesi compiles the entry script and its transitive Sesi modules to bytecode, omits source files, and bundles the runtime and registered assets.
Existing output is preserved unless overwrite is explicitly enabled:
game.build("build/MyGame", {
overwrite: true,
icon: "icon"
})icon accepts a registered texture name or a local image path. If it is omitted, a registered texture named icon is selected automatically; otherwise the package supplies a placeholder application icon.
Runtime security
The game window uses Electron context isolation with Node integration disabled. Navigation and new-window creation are denied, and packaged applications use a deny-by-default capability manifest for network origins, external links, filesystem roots, clipboard access, localhost servers, and process access.
API overview
The module exports Game.VERSION, Game.create, Game.vec2, Game.vec3, Game.quat, and Game.color. A game provides scene management, asset registration, lifecycle callbacks, input, storage, development execution, and desktop builds. The installation, examples, assets, physics, lifecycle, packaging, and security information required to use the package is included in this README.
Requirements
- Node.js 20 or newer
- A current Windows, macOS, or Linux version supported by Electron
@misterscan/sesiinstalled separately- Local mode (
sesi -l) for development runs and builds
License
MIT
