LeCodesdocs

Соглашения

Сквозные правила, действующие везде в SDK. Каждая справочная страница их предполагает.

Без импортов — всё глобально

Вся поверхность SDK (Scene, Sprite, UIScreen, Vec3, fetch, …) внедряется на этапе сборки; пользовательский код её никогда не импортирует. Единственные import в проекте — это относительные пути к его собственным файлам (import { hud } from './ui/hud') и к его ассетам (import hero from './hero.png'). Голый импорт пакета — ошибка сборки.

Точка входа: файл без экспортов. В многофайловом проекте он связывает остальные вместе и запускает приложение (Router.init(home) или scene.open()).

Ассеты: ссылайся на файл проекта через import или встроенный макрос asset('./path') — это переписывание на этапе компиляции, поэтому путь должен быть строковым литералом. Удалённые https://… URL — обычные строки.

Время

  • setLoop(dt => …) срабатывает каждый кадр; dt — это секунды с прошлого кадра (~0.016 при 60 fps). Движение, независимое от кадра, — position += speed * dt.
  • setTimeout / setInterval принимают миллисекунды.
  • Длительности анимаций — миллисекунды: animate({ duration }) и UI .animateTo() / .animateFrom() (duration, delay).

Пространство, единицы, углы

2D (Scene2D) 3D (Scene) UI / экран
Оси X вправо, Y вверх правая система, Y вверх, вперёд = −Z X вправо, Y вниз
Единица 1 мировая единица = 1 логический px при zoom 1 ≈ метры логические px (dp/pt)
Углы rotation в градусах, CCW eulerAngles в градусах
  • Аргументы-«сырые углы» — радианы (Quat.fromAxisAngle, Mat4.rotate*, Vec2.rotate); эйлеровы свойства и фабрикиградусы (node.rotation, Quat.fromEuler). DEG2RAD / RAD2DEG — константы времени компиляции для конвертации.
  • Экранные координаты (clientX/clientY, device.width/height) — логические px (как iOS pt / Android dp), никогда не физические пиксели; device.pixelRatio — отношение физических к логическим.
  • Одна ловушка знака: в 2D-мире Y смотрит вверх, но экранный Y и пространство якоря спрайта смотрят вниз (anchor: [0.5, 1] = низ-центр = «ноги»).

Цвета

Везде, где принимается цвет, работает всё это (ColorInput): hex-строки "#e33", "#e33c", "#ff3333", "#ff3333cc"; упакованный int 0xff3333 (только 24-битный RGB — альфу нельзя передать числом); нормализованные массивы дробных [r, g, b] / [r, g, b, a] (0..1).

Note

hex — единственная строковая форма. CSS-стиль rgba(...) / именованные цвета не парсятся — они молча становятся непрозрачным чёрным. (UI-стили — исключение: они идут в UI-движок со своим парсером — см. Стилизацию UI.)

Семантика значений в математике

Vec2 / Vec3 / Quat / Mat4 — изменяемые структуры с чистыми методами: поля можно присваивать (v.x = 3), но каждый метод возвращает НОВОЕ значение и никогда не меняет источник. Они итерируемы и взаимозаменяемы с сырыми кортежами — [0, 1, 0] работает везде, где принимается Vec3.

Геттеры трансформа узла возвращают свежие копии (семантика значений, как в Unity):

TypeScript
node.position.x = 3                                   // ✗ тихий no-op — меняет отброшенную копию
node.x = 3                                            // ✓ сеттер одной оси
const p = node.position; p.y += 1; node.position = p  // ✓ поменять локальную, присвоить обратно

События

  • Сцены, узлы, device, WebSocket, медиаплееры: addEventListener(channel, cb) / removeEventListener(channel, cb).
  • UI-элементы вместо этого используют чейнящиеся методы on* (.onClick(cb), .onChange(cb)).
  • События указателя: click срабатывает на отпускании над целью; touchstart срабатывает на нажатии, и его объект события может ev.track({...}), чтобы захватить остаток жеста. См. События указателя и жесты.

Цепочки

Конструкторы принимают объект опций; настраивающие сеттеры возвращают this, поэтому сборка читается одной цепочкой. UI-фабрики чейнят .style() и on*. Возможности узла прикрепляются как аспекты и тоже чейнятся:

TypeScript
const hero = new Sprite({ texture })
  .aspect(SpriteAnimation, { size: [32, 48], fps: 10, clips: { walk: [1, 2, 3] } })
  .aspect(Shape2D, { box: [16, 8] })
  .aspect(Physics2D, { motion: 'dynamic', fixedRotation: true })
hero.anim.play('walk')          // каждый аспект добавляет именованный аксессор

См. Аспекты.

Физика владеет динамическими трансформами

Как только у узла есть dynamic-тело (Physics / Physics2D), шаг физики пишет его трансформ. Не задавай node.position каждый кадр — управляй телом через velocity / applyImpulse (кинематические тела: moveTo). Чтение node.position / node.worldPosition всегда корректно; SDK автоматически пересинхронизируется с нативным слоем.

Гейтинг хоста — возможности, которых может не быть

Некоторые возможности зависят от сборки хоста. При отсутствии они молча делают no-op; проверяй через:

  • Physics.supported (3D-физика), Physics2D.supported (2D-физика)
  • QRScanner.isSupported
  • device.setPreciseTouch() — no-op там, где у платформы нет понятия объединённого ввода

Жизненный цикл

  • Всё запущенное в onOpen экрана должно останавливаться в onClose (clearLoop, clearInterval, ws.close()), иначе продолжит работать при навигации.
  • Объекты, оборачивающие нативные ресурсы, освобождают их явно там, где есть метод: node.destroy() (2D/3D-узлы), player.dispose() (медиа — бросает при любом использовании после), Texture2D.destroy(), response.dispose() (тела fetch). У 3D Texture освобождения нет — она живёт до закрытия движка.