LeCodesdocs

Anatomy of a project

A LeCodes project is plain TypeScript — but a few rules differ from a regular codebase, and every page of this guide assumes them. Five minutes here saves confusion everywhere else.

Everything is a global — no imports

The whole SDK surface (Scene, Sprite, UIScreen, Vec3, fetch, …) is available in every file without importing anything. The build injects the implementation of what you use and strips what you don't, so the globals cost nothing.

The only import statements a project may contain are relative paths — to its own files and assets:

TypeScript
import { hud } from './ui/hud'      // ✓ your own module
import hero from './hero.png'       // ✓ an asset — resolves to its bundled URL
import _ from 'lodash'              // ✗ build error: no package imports

There is no npm here by design: the runtime on the device is not Node and not a browser, and the compiler needs to see all the code to shake it down to kilobytes.

The entry point

The file with no exports is the entry point. A small project is often just one file; in a multi-file project the entry wires the other modules together and starts the app — for a UI app that's Router.init(home) or screen.open(), for a game scene.open().

Assets

Files in your project (images, models, sounds, fonts) are referenced two ways — an import, or the inline asset() macro:

TypeScript
import hero from './hero.png'                          // same thing, two spellings
const tex = await Texture2D.load(asset('./hero.png'))

asset() is a compile-time macro: the bundler rewrites it into the resource reference, so the path must be a string literal — asset(someVariable) is a build error. Remote https://… URLs don't need it; pass them as plain strings.

Time: the frame loop and timers

TypeScript
setLoop(dt => {           // fires every rendered frame
  player.x += 120 * dt    // dt is SECONDS since the last frame (~0.016 at 60 fps)
})

setTimeout(() => {}, 500) // timers take MILLISECONDS, like the web

One convention to internalize early: setLoop's dt is seconds — scale movement by it and your app runs the same at any frame rate. Timers and animation durations (animate, UI .animateTo()) are milliseconds.

And its companion rule: a loop runs until cleared. Whatever a screen starts in onOpen, it must stop in onClose — see lifecycle.

What the compiler does

When you hit run, the compiler packs the project into a single portable app.js: it injects the SDK, resolves assets, inlines vector math, and tree-shakes aggressively — down to unused methods of classes. That bundle is what every platform executes, with rendering, layout and physics running as native engine code — no WebView anywhere. If you're curious how the pieces fit, see Architecture.

The practical consequence: an app ships as megabytes, not tens of megabytes, and behaves the same in the browser preview, on iOS, Android, Windows, macOS and Linux.

Where to look things up

  • Conventions — units, coordinate systems, colors, value semantics: the rules every API page assumes.
  • Host globalssetLoop, timers, asset(), console.
  • The rest of the API Reference — every global, with signatures and units.

What's next

Pick a track from the overview and start building.