Features
Eleven subsystems, one app object
Every subsystem below is an extension: you pass it to createApp and it adds one service to the app plus the components that go with it. Nothing is registered that you did not ask for, and each one links to the skill page an agent would read.
@ignifx/core
Kernel, scripts and scenes
createApp owns the frame loop and the extension host. A World holds SceneInstances, which hold Entitys, which hold a Transform and components; a Script is a component with lifecycle callbacks. Fields are declared with a schema rather than decorators (ADR-0004), which is what makes a component serializable, inspectable in devtools, and patchable on hot reload. Scenes and prefabs are the same ignifx.scene file (ADR-0005): world.instantiate stamps one out, overrides survive a round trip.
createAppWorldEntityTransformComponentScript.defineSignalserializeScene
@ignifx/core
Rendering on Babylon Lite
ignifx does not rasterise anything: Babylon Lite does, exclusively through WebGPU (ADR-0001). The engine owns the loop and hands Lite a scene. Camera, Light, MeshRenderer, Model, Environment and PostProcessStack are ignifx components; Lite objects stay behind the adapter boundary and are reachable only through documented .lite escape hatches (ADR-0002). Device loss is recovered at both layers, and material families can be warmed up before a scene is registered (ADR-0014).
CameraLightMeshRendererModelEnvironmentPostProcessStackapp.renderer.warmUp
@ignifx/core
Assets
Everything a game loads is reached by address through app.assets and comes back as an AssetHandle<T> you release when you are done. Loads are cancellable (IGX-0502), reference counts unload at zero after a gcDelay, and a hot swap replaces an asset in place. Delivery has one rule worth memorising: before app.start() a finished load settles immediately; once the loop is running it settles in PreUpdate.
app.assets.loadAsyncAssetHandleMeshAssetSceneAssetModelAsset
@ignifx/input
Input
@ignifx/input turns keyboard, mouse, gamepad and touch into named actions. Action maps, bindings, composites and processors, and control schemes live in an .input.json document, so rebinding is data and not a code change. Pointer lock, the cursor, and PlayerInput are part of the same surface. Positions are reported in backing-store pixels, which is the space Camera.screenToRay reads.
input()app.input.actionsdefineInputActionsPlayerInput<Pointer>/position
@ignifx/physics
3D physics
Rigid bodies, the collider set, triggers, a kinematic CharacterController, raycasts and shape queries, a layer matrix, and interpolation between fixed steps. Physics runs inside FixedUpdate, so a query answers only after one completed fixed step (IGX-0902). Collision identity has a documented waiver until Lite reports body identities upstream (ADR-0013).
physics()RigidbodyBoxColliderCharacterControllerapp.physics.raycast
@ignifx/2d · @ignifx/physics-2d
2D toolkit and 2D physics
@ignifx/2d draws sprites: SpriteRenderer and SpriteAnimator, atlases, Tilemap, sorting layers, pixel-perfect rendering, parallax, and 2D picking, all under a Camera2D with pixels per unit. @ignifx/physics-2d simulates them with Rapier 2D (ADR-0006): Rigidbody2D, the 2D colliders, triggers, CharacterController2D, one-way platforms, queries and the same layer matrix.
twoD()physics2d()Camera2DSpriteRendererTilemapRigidbody2DCharacterController2D
@ignifx/audio
Audio
app.audio is a mixer tree described by an audiobuses document, with AudioSource, AudioListener and MusicPlayer on top of it and two backends underneath. Browsers start audio locked until a user gesture: plays made before then are queued rather than lost, and a headless app is never locked.
audio()app.audio.unlockAudioSourceAudioListenerMusicPlayer
@ignifx/3d
3D toolkit
The layer that turns core plus physics plus input into a 3D game: character and camera rigs that do not clip through walls, an Animator state machine driving a rigged model, navigation baked from level geometry, and the environment helpers. Navigation is WebAssembly (ADR-0017) and is loaded only when a navmesh is actually baked.
threeD()ThirdPersonControllerThirdPersonCameraAnimatorNavMeshSurface
@ignifx/ui
UI
@ignifx/ui puts one absolutely positioned overlay over the canvas and lets a game mount React, Svelte, Vue or plain DOM into named layers inside it (ADR-0008). It owns three scaling modes, input focus routing between the page and the game, WorldAnchor for markers that track an entity, text components on Lite's text renderer, touch and dialog helpers, and app.i18n.
ui()app.ui.layerWorldAnchorDialogVirtualJoystickapp.i18n
@ignifx/electron
Electron
The desktop half: createGameWindow in the main process, a sandboxed CommonJS preload bridge, an ignifx://app protocol that serves the asset manifest with Range support, and a renderer electron() extension that switches app.platform.kind and swaps storage for a file-system backend. The security baseline of CONSTITUTION.md §9.2 is asserted twice — from the pure option builders and inside a running Electron app.
electron()createGameWindowapp.desktopapp.storage
@ignifx/devtools
Devtools and hot reload
app.devtools opens an overlay with stats, a virtualised scene tree, a schema-driven inspector where every field kind is editable, assets, input, audio, physics with Lite's debug viewer, a console, and a per-phase timing graph. Closed, it registers no systems and no subscriptions. app.hotReload patches a script's prototype in place, or recreates the instance with its props when the schema shape changed.
devtools()app.devtools.openapp.hotReload.applyonHotReload