A native engine for games and apps in one TypeScript project

3D on Filament, Jolt and Box2D physics, skeletal animation with IK, navmesh, particles, terrain, a 2D engine and AR — all in a C++ runtime, not a browser wrapper. One bundle runs on phones, computers, in a VR headset and on the web.

iOSAndroidQuestWindowsLinuxmacOSWeb
7platforms from one bundle
3graphics APIs: Metal, Vulkan, OpenGL
~6 MBan app with 3D and physics
<1 sto compile the whole project
Rendering

3D rendering on Filament.

PBR materials and lighting

Metallic-roughness materials, IBL environments from KTX, a sun with shadows, skybox, height fog, bloom and tone mapping — ACES, filmic or neutral. lecodes lightmap bakes the static part of a level into lightmaps; the dynamic part lives on top in real time.

Your own shaders

.mat materials in the Filament language compile locally with lecodes shaders and load through Material.load on every target. Updated the engine? lecodes shaders update recompiles everything for you.

Big worlds

Terrain, vegetation, instancing for thousands of identical objects, decals, a particle system with ribbons and mesh particles, noise for procedural content. All of it is SDK classes, not third-party plugins.

Physics and characters

Jolt, animation and navigation.

Jolt physics

Bodies and shapes, triggers, contact events, raycasts and a ground probe, ragdolls, a character controller on top of CharacterVirtual and wheeled vehicles. The same simulation on every host, including the headless run — the physics in a test is real, not a stub.

Skeletal animation

Clips, layers and blending, IK, root motion, locomotion, foot placement on uneven ground and dynamic bones for tails and cloaks. Models from Mixamo, Unity and Unreal come through the asset pipeline, including retargeting to another skeleton.

Navigation, input and sound

A navmesh on Recast/Detour: lecodes navmesh bakes it, agents walk it at runtime. One Input for keyboard, mouse, touch and gamepad — a gamepad button is just a key. Positional sound: sources and zones attached to scene nodes.

2D

A separate 2D engine for games.

Sprites and animation

Sprites, sprite sheets and frame animation, layers with Y-sorting for pseudo-3D, a camera of its own with zoom and follow. A click or a tap on the scene returns the object it hit.

Tile maps

Tilemaps and tilesets with autotiling: paint an area and the engine picks the edges and corners itself. The map is a scene node like everything else.

Box2D physics

Bodies, shapes, triggers, a 2D character controller and one-way platforms for platformers. Collisions arrive as events on the node. Nodes, aspects and the game loop work the same way as in 3D.

Around the engine

AR, UI and verifiability.

AR

ARScene is the same scene, only anchored in the real world: a model is placed on a table or attached to an image, and control gestures are one line. Works in the le.codes app on iOS and Android.

UI on top of the scene

HUD, menus and screens — on the Yoga flexbox layout in the same file as the scene. Signals update text without a re-render, lists are virtualized natively. No second project for the UI.

Deterministic time

In a headless run setLoop, physics and aspects advance in fixed 1/60 steps driven by the script, not the clock: a test that passed once passes always. A failed step saves the frame as JSON and PNG — a red step explains itself.

What it looks like in code

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.

TypeScript
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:

TypeScript
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.

What's around the engine

Tools

Scene, assets and tests — in the terminal and in the editor, no third-party programs.

scene.3d

Scene editor

The 3D-scene tab in the editor, and `lecodes scene` locally: tree, inspector, gizmo, materials. Edits are written straight into `.scene.ts`, and edits from the IDE are picked up live — the editor and the code never argue about who's in charge.

ui.editor

Asset pipeline

FBX → GLB with textures inside, `doctor` for GLB (bone limit, KTX2, scale), animation retargeting from another skeleton — including Mixamo, Unity `.anim` and reading Unreal `.uasset`. All of it is `lecodes assets`.

build.ts

Headless render and tests

`lecodes render` and `lecodes test` run the real bundle with real physics without a device or a browser. In headless, 3D comes back as JSON; for pixels there is `--desktop` through the native host.

Modules are optional — don't use 3D, and it never enters the bundle. An app without a scene weighs about 2 MB; with 3D and physics about 6.

How it's built

The engine is a set of native C++ libraries that the app's JavaScript talks to over a narrow bridge. QuickJS runs the scripts; layout, rendering, physics and animation are done natively — so 60 frames per second don't depend on JavaScript speed.

SubsystemLibraryWhat it does
3D renderingFilamentPBR, IBL, shadows, bloom, lightmaps, KTX2
3D physicsJoltbodies, characters, vehicles, ragdolls, events
Animationcreator-animclips, layers, IK, root motion, dynamic bones
Particlescreator-particlesemitters, curves, ribbons, mesh particles
NavigationRecast / Detournavmesh and agents
2Dsokol + Box2Dsprites, tilemaps, 2D physics
UIYogaflexbox layout, drawn by the host

The chisel compiler, written in Rust, builds the project into a single app.js and strips everything unused, down to individual class methods. The bundle header tells the host which engines to bring up: an app without 3D never loads Filament at all. The detailed engineering description is on the Architecture page.

Platforms and graphics APIs

PlatformGraphicsHost
iOS, macOSMetalSwift, one code base for both
AndroidOpenGL ESKotlin + the native core; a separate Quest build on OpenXR
Windows, Linux, Astra LinuxVulkan or OpenGLC++ host, one process, ~11 MB on disk
WebWebGL 2the full host on wasm, or a light one at ~31 KB without wasm
Headless—Bun: real physics, 3D as JSON — for tests and AI agents

Honestly about the limits: AR works only in the app, not on the web; the light web host can't do 2D; headless doesn't rasterize 3D. New engine capabilities — animation v2, 2D physics, vehicles, terrain, lightmaps — land on desktop first and then reach the mobile hosts; platform parity is checked by an automatic matrix over every API member.

What's next

  • Multiplayer. The network layer on yojimbo (UDP) is built together with the replication core; the remaining phases are in progress. The targets are desktop, Android and iOS: the web has no UDP by design.
  • A 2D scene editor and a 2D-games track in the documentation.
  • Video. An engine overview will appear on this page.

The platform's assistant knows the engine from the same documentation you do: it writes scenes, physics and aspects with this same API and sees the result of its code through the headless render. But the engine doesn't require the assistant — it's ordinary TypeScript in your folder, and lecodes compile builds it without a server or an account.

Try the engine right now

The editor, the engine and the build are free. Subscribe to our Telegram and enter the promo code tg_sub26 at your first top-up: a 50% discount and 2,500 credits as a gift.

Open the editor
Partnership

Let's discuss your project.

A game, an app with 3D, embedding the engine into your own product, or a question about what it can do — write to us and we'll reply to the email you leave.

Protected by Yandex SmartCaptcha. By submitting, you agree to the processing of your data.