Skip to content

@awaken/runtime

Everything that runs while your game plays: the physics engine (Rapier), the script host, the play/scene lifecycle, input, audio, in-game UI, and skeletal-animation playback. It depends on @awaken/core and Rapier (WASM) - not on @awaken/render, so the whole runtime is headless-testable.

ts
import { Runtime, PlayController, ScriptHost, RigidBody, Collider, RapierBackend } from "@awaken/runtime";

The Scripting API is the user-facing surface over this package; the Physics section covers the physics feature set. This page is the underlying types.

runtime (systems)

SymbolSignatureDescription
System(world, dt) => voidA per-frame simulation function.
RuntimeclassHolds an array of Systems; tick(world, dt) runs them in order.
DEFAULT_SYSTEMSSystem[] ([])Empty by default - gameplay lives in scripts (the ScriptHost) and physics is driven by the PhysicsRunner, not built-in tick systems.

The play lifecycle

PlayController owns Edit → Play → Stop. On Play it snapshots the scene, builds the physics sim + script host, and starts play-on-start audio; on Stop it tears them down and restores the snapshot (optionally keeping your authored edits). See Preview & Play.

SymbolSignatureDescription
PlayState"edit" | "play" | "paused"The controller's state.
PlayControllerclassplay(), pause(), resume(), stop(keepEdits?), update(dt), state, markEdited()/hasEdits(), requestRestart(). Constructed with the world, Runtime, component types, and optional services (registry, audio, hud, physics, ui, scenes, game, prefab source, log sink).

update(dt) runs the frame in order: apply any queued scene swap → step physics → run systems → run scripts (which see updated transforms + real contacts) → sync script/animation-moved colliders back into physics.

Scripting

The script host runs each entity's Script behaviours and exposes the ScriptApi to them. Script parameters are discovered from the compiled class so the Inspector can edit them.

SymbolSignature / ShapeDescription
ScriptApiinterfaceThe full script-facing surface: transform helpers, find/findByTag, spawn, events (emit/on), timers (after/every), loadScene/reloadScene, save/load/state, moveAndSlide, raycast, playSound, setHud, ui, log. Documented field-by-field in Scripting API.
ScriptBehaviorinterfaceThe lifecycle hooks a script implements: onStart, onUpdate(api, dt), onDestroy, onCollision/onCollisionEnter/onCollisionExit.
ScriptComponentType + interface{ scripts: ScriptEntry[] } - an entity can carry several behaviours.
ScriptEntry{ name; params?; refs?; enabled? }One attached behaviour: its script id, per-instance parameter overrides, entity-reference fields, and enable flag.
TagComponentType + interface{ value: string } - a string tag for findByTag lookup (find by tag, not by name).
ScriptParam{ name; type; default; component?; options?; description?; min?; max? }A discovered public field (drives the Inspector control).
discoverScriptParams(factory, source?) => ScriptParam[]Discover a script's editable public fields by combining instance introspection + source parsing (TS types are erased at runtime).
ScriptRegistryclassregister(name, factory), get, unregister, names() - the compiled-script lookup.
ScriptHostclassRuns the behaviours: update(world, dt, contacts?) and destroyAll(world). Owns per-slot instances, timers, event handlers, and collision-edge tracking; hot-restarts a slot when its params change during Play.
SpawnFn(prefab, opts?) => Entity | nullPrefab instantiation hook the app supplies.

See Script Parameters, Events & Timers, and Input.

Physics

Physics is engine-agnostic: Awaken3D talks only to PhysicsBackend/PhysicsWorld, implemented today by Rapier (WASM). The ECS components author the bodies; the PhysicsRunner builds and steps the sim during Play.

Components

SymbolSignature / ShapeDescription
RigidBodyComponentType + interface{ velocity, useGravity, restitution } (defaults: 0 velocity, gravity on, restitution 0.3).
ColliderComponentType + interface{ shapes: ColliderShape[] } - one body, many shapes.
ColliderShape{ kind, center, size, radius, height, mesh, convex, trigger, enabled, pinned? }One shape: a primitive or a collision mesh, each independently a trigger/solid/toggleable.
ColliderKind"box" | "sphere" | "capsule" | "cylinder" | "mesh"Shape kind.
newColliderShape(kind?) => ColliderShapeConstruct a default shape.
primaryShape(c) => ColliderShapeThe first enabled shape (drives the AABB fallback + character capsule).
GRAVITY-9.81Default gravity constant.
detectCollisions(world) => [Entity, Entity][]Pure AABB overlap test - the fallback when no physics engine is running.
physicsSystemSystemThe legacy hand-rolled semi-implicit-Euler integrator (superseded by the Rapier runner in Play).

See Rigidbody, Colliders, and the Character Controller.

Backend & runner

SymbolSignatureDescription
PhysicsBackendinterface{ name, supportsSoftBody, init(), createWorld(gravity) } - a physics engine implementation.
PhysicsWorldinterfaceA live sim: step, bodies, colliders, joints, raycast, drainContactEvents, moveCharacter, and debug line geometry.
RapierBackendclass implements PhysicsBackendThe Rapier (WASM) implementation.
PhysicsRunnerclassBridges the ECS to a PhysicsWorld: prewarm, start(world), addEntity, step(world, dt), syncColliderPoses, contacts(world), moveCharacter, raycastForScript, plus debugLines/debugTriggers for the physics debug view.
createMeshShapeFor(…) => ShapeDesc | nullBuild a convex-hull/trimesh collision shape from a mesh.
BodyType, ShapeDesc, BodyDesc, ColliderDesc, JointDesc, JointMotor, JointSpring, RaycastHit, ContactEvent, CharConfigtypesThe backend's descriptor + event vocabulary (see Joints, Queries & Events).

Scenes & state

SymbolSignatureDescription
SceneDirectorclassThe runtime scene library + deferred transition queue. register/registerAll, load(name), reload(), take() (drained each frame by the PlayController). Loads apply at the top of the next frame, never mid-script.
GameStateclassstate (in-memory session bag surviving scene loads) + save(key, value)/load(key) (namespaced localStorage) + resetSession().
KVStoreinterface{ getItem, setItem, removeItem } - the storage abstraction, so save/load is testable without a browser.

See Scenes & Persistence.

Input

SymbolSignatureDescription
InputclassPer-frame input: isDown(key), mouseDX/mouseDY (per-frame delta for mouse-look), pointerLocked, plus the setters the game loop drives (setKey, addMouse, clearMouse, setPointerLocked, clear).

Scripts read this via api.input. See Input.

Audio

SymbolSignatureDescription
AudioEngineinterface{ play(clip, opts?) } - pluggable so the runtime stays headless-testable.
NoopAudioEngineclassThe headless no-op backend.
PlayOpts{ volume?, loop? }Playback options.
AudioSourceComponentType + interface{ clip, volume, loop, playOnStart } - an entity that plays a clip on Play start.

See Audio.

In-game UI

SymbolSignatureDescription
UINodeComponentType + interfaceA screen-space UI element (kind: text | panel | button | image, anchor, x/y/w/h, text, fontSize, color, bg, opacity, visible, and - for image and animation - image/fit/rotation/scaleX/scaleY/font). Rendered as a DOM overlay in both the editor Game view and the shipped player.
uiNodeStyle(n: UINode, scale?) => CSSPropsPure UINode → CSS map (one source of truth, unit-testable). scale multiplies every pixel dimension (the overlay passes viewportHeight / uiReferenceHeight).
UIAnimatorComponentType + interface{ clip, playing, speed, time } - plays a UIClip on a widget's UINodes (tracks address them by name).
driveUIAnimators(world, dt, clipById) => voidAdvance every UIAnimator and write its clip's sampled values onto the widget's UINodes. Call once per frame before the overlay syncs.
applyUIClip(clip, time, resolve) => voidSample every track of a UIClip at time and write the values onto the resolved target nodes (loops if the clip loops).
sampleTrack / clipDurationhelpersLinear-interpolate a keyframe list at t; the latest keyframe time across a clip's tracks.
UIClip / UITrack / UIKey / UIProptypes (re-exported from @awaken/core)The renderer-agnostic keyframe model a UIAnimator plays (imported from Unity .anim).
HudSink / NoopHudSinkinterface / classThe HUD-text sink (api.setHud).
UIStateclassButton-click handler registry (api.ui.onClick), fired by the overlay.
UIOverlayclassThe DOM overlay that renders UINodes and dispatches clicks to UIState.

Scripts drive UI through api.ui: setText / setImage / show / hide / onClick, plus play(name, clip) / stop(name) for UI animation. See UI and Scripting UI.

Animator & animation system

SymbolSignatureDescription
AnimatorComponentType + interfacePer-entity playback state: clip/skeleton/time/speed/loop/playing, the crossfade fields (fadeClip/fadeTime/fadeDuration/fadeElapsed), the play window (clipStart/clipEnd), and root-motion output (rootDx/rootDz, flatRootY).
playClip(anim, clip, opts?) => voidStart playback, crossfading over opts.fade (blends the two clips via core blendPoses); idempotent.
advanceTime / advanceTimeRangeclock helpersAdvance a playback clock (loops both directions; non-looping clamps); the Range form trims to a [start,end] window.
animationSystem(world, dt, deps: AnimationDeps) => voidAdvance every Animator, crossfade-blend, extract root motion, apply foot IK, CPU-skin its mesh, and upload the deformed positions; also writes bone-anchor poses and builds/drives a ragdoll when one is flagged.
AnimationDepsinterface{ clip, skeletonFor, skinFor, upload, footIK? } - outside-the-ECS dependencies, injected for testability (footIK supplies the ground source + config).
AnimStateMachine / animGraphSystemComponentType / (world, deps) => voidParam-driven state graph that chooses the Animator's clip; LOCOMOTION_GRAPH is a built-in. Drives via api.setAnimParam/setAnimTrigger.
BoneAnchorComponentTypeMirrors one named skeleton bone onto an entity so attachments ride the animation.
Ragdoll / buildRagdollBodies / ragdollBoneMatricescomponent + helpersHands a skinned character to physics (joint-linked bodies) and drives the skeleton from the sim. Experimental.

The pure skinning + blend + root-motion + graph + foot-IK math lives in @awaken/core. See Animation.

Particle engine

SymbolSignatureDescription
ParticleEngineclassOwns every live emitter pool and every in-flight one-shot burst. tick(world, dt) advances each active ParticleEmitter (and each burst), simulating via core's simulateEmitter and uploading through deps. burst(effectId, opts?) spawns a transient one-shot that retires itself once exhausted. clear() drops everything.
ParticleDepsinterface{ effect(id), upload(handle, data, count, opts), remove(handle) } - the seam that keeps @awaken/runtime free of any renderer or asset-store import. effect resolves an id against the project; upload/remove are backed by the renderer's particle buffers.

Pools are side-state keyed by entity: they are never serialized, and they bypass the ECS dirty-set entirely - the same rule CPU skinning follows, so a per-frame particle update never triggers a draw-cache rebuild. A burst is deliberately not tied to the script that fired it, so destroying an object mid-frame doesn't cut off its own explosion. See Particles.

See also

  • Scripting API - the user-facing surface over ScriptApi/ScriptBehavior.
  • Physics Overview - the physics feature set backed by PhysicsRunner/Rapier.
  • Component Reference - RigidBody, Collider, Script, Tag, AudioSource, Animator, UINode, UIAnimator fields.
  • Preview & Play - the play lifecycle PlayController drives.
  • @awaken/core - the World, Entity, and animation math the runtime builds on.

Awaken — browser-native WebGPU game engine.