ignifx0.x · unpublished
GitHub

Recipes·skills/ignifx/references/recipes/load-a-model.md

Load a model

<!-- Generated by `pnpm docs:recipes`. Do not edit by hand. -->

A .glb or .gltf file loads as a ModelAsset, and a Model component instantiates it under an entity. Load before app.start() so the mesh is part of the scene Babylon Lite registers; a model added later still appears, a few frames after its material family is compiled (app.renderer.warmUp pays that cost up front).

One release per load: an asset() field holds the handle but never owns its reference count.

typescript
import { Camera, Light, Model, createApp } from "@ignifx/core";import type { AssetHandle, ModelAsset } from "@ignifx/core";const canvas = document.querySelector("canvas");if (!(canvas instanceof HTMLCanvasElement)) {  throw new Error("ignifx renders into a <canvas> element.");}const app = await createApp({  canvas,  settings: { assets: { root: "assets" }, rendering: { features: { shadows: true } } },});// A camera is an entity with a `Camera` component: the entity's transform is the view.const eye = app.world.createEntity("Main Camera");eye.transform.localPosition.set(0, 1.6, -4);eye.transform.lookAt({ x: 0, y: 0.8, z: 0 });eye.addComponent(Camera, { fov: 55, near: 0.1, far: 100 });// Only directional and spot lights can cast shadows in this Babylon Lite version (IGX-0703).const sun = app.world.createEntity("Sun");sun.transform.localPosition.set(3, 6, -2);sun.transform.lookAt({ x: 0, y: 0, z: 0 });const light = sun.addComponent(Light, { type: "directional", intensity: 3 });light.shadows.enabled = true;light.shadows.technique = "pcf";// The app is not running yet, so `loadAsync` settles as soon as the file is decoded and `handle.value`// is safe below; once `app.start()` has run, loads settle in the `PreUpdate` phase of a frame.const hero: AssetHandle<ModelAsset> = await app.assets.loadAsync<ModelAsset>("models/hero.glb");const actor = app.world.createEntity("Hero");actor.addComponent(Model, { model: hero, castShadows: true, receiveShadows: true });await app.start();// glTF node names are the attachment points: parent an entity under one to carry a weapon or a hat.const model = actor.requireComponent(Model);const torch = app.world.createEntity("Torch");model.attachToNode("hand.R", torch);app.log.info("model nodes:", model.nodes.size);// Teardown. The entity's components go with it; the handle is released by whoever loaded it.window.addEventListener("pagehide", () => {  actor.destroy();  hero.release();  app.dispose();});

Source: examples/recipes/load-a-model/main.ts