Scene, light, shadows, physics and controls — one file. No imports, no node_modules: the whole SDK is available as globals, and only what the project references ends up in the bundle. A node's behaviour is an Aspect, the logic of the whole scene a System; no empty nodes with a loop and hand-written tick(), and the compiler derives the accessor name: Aspect<'health', …> becomes node.health.
const scene = new Scene({ skybox: '#202030', bloom: true })
const ground = Mesh.plane({ material: Material.lit({ color: '#333' }), normal: [0, 1, 0], scale: 20 })
.aspect(Shape, { box: [10, 0.1, 10] })
.aspect(Physics, { motion: 'static' })
const crate = Mesh.box({ material: Material.lit({ color: '#e33' }), position: [0, 4, 0] })
.aspect(Shape, {}) // the shape is derived from the mesh
.aspect(Physics, { mass: 2 }) // a dynamic body by default
crate.addEventListener('enter', other => console.log('hit:', other.name))
scene.add(Light.sun({ shadowsQuality: 2 }), ground, crate)
scene.camera.position = [0, 3, 6]
scene.open()
setLoop(() => {
if (Input.key('Space')) crate.physics.applyImpulse([0, 6, 0])
})
A 2D scene — in the same language:
const scene = new Scene2D({ background: '#10131a' })
scene.layer(1).ySort() // layer 1 is sorted by Y
const load = async () => {
const tex = await Texture2D.load(asset('./hero.png'))
scene.add(new Sprite({ texture: tex, anchor: [0.5, 1], layer: 1 }))
}
load()
scene.addEventListener('click', ev => {
console.log('tap on', ev.target?.id ?? 'empty space', ev.worldX, ev.worldY)
})
scene.open()
Both examples compile with lecodes compile in under a second into a single app.js that runs identically on every platform.