@awaken/core
The engine foundation: math, the entity-component World, transforms, scene serialization, and the data models other packages share (skeletal animation, the animation graph, the humanoid slot map, particle effects, UI clips, MIDI options). It imports no package at all, internal or external, so every symbol here runs the same in the editor, the player and a worker, and every other package builds on it.
Everything is re-exported from the package barrel:
ts
import { World, Transform, mat4FromTRS, serializeWorld } from "@awaken/core";The modules below map one-to-one onto files in packages/core/src. packages/runtime/src/layering.test.ts fails the build if a non-type import of any package lands in core.
math
Column-major 4×4 matrices (WebGPU/WGSL convention) stored as Float32Array; vectors and quaternions are plain objects. Matrix functions write into an out argument and return it, so you can reuse buffers in hot loops.
| Symbol | Signature | Description |
|---|---|---|
Vec3 | { x: number; y: number; z: number } | 3-component vector (plain object). |
Quat | { x, y, z, w: number } | Quaternion (plain object), w = 1 identity. |
Mat4 | Float32Array (length 16) | Column-major 4×4 matrix. |
vec3 | (x?, y?, z?) => Vec3 | Construct a vector (defaults 0). |
quat | (x?, y?, z?, w?) => Quat | Construct a quaternion (defaults identity). |
mat4 | () => Mat4 | A zeroed 16-float matrix. |
snap | (v, step) => number | Round v to the nearest multiple of step (step ≤ 0 → unchanged). |
mat4Identity | (out?) => Mat4 | Write the identity matrix. |
mat4Multiply | (out, a, b) => Mat4 | out = a · b (column-major). |
mat4FromTRS | (out, t, r, s) => Mat4 | Compose translation/rotation/scale into a matrix. |
mat4Invert | (out, m) => Mat4 | Invert m (identity fallback for a singular matrix). |
mat4OrthoZO | (out, l, r, b, t, near, far) => Mat4 | Orthographic projection, WebGPU clip space (z ∈ [0,1]). |
mat4TransformPoint | (out, m, p) => Vec3 | Apply a matrix to a point, dividing by w (or 1). |
mat4TransformDir | (out, m, v) => Vec3 | Upper 3×3 only: rotation and scale, no translation. |
mat4TransformNormal | (out, m, n) => Vec3 | Carry a normal to world space by the cofactor (inverse-transpose) matrix, the CPU twin of the shaders' normalToWorld. Correct in direction only; normalize before use. |
quatFromEuler | (out, x, y, z) => Quat | Euler (XYZ, radians) → quaternion. |
quatToEuler | (q) => Vec3 | Quaternion → Euler angles (radians), inverse of quatFromEuler. |
quatMultiply | (out, a, b) => Quat | Quaternion product. |
quatFromAxisAngle | (out, ax, ay, az, angle) => Quat | Rotation of angle radians about an axis. |
quatFromTo | (from, to) => Quat | The rotation turning from onto to (shared by foot IK and the ragdoll). |
quatNormalize | (out) => Quat | Normalize in place (guards against drift). |
quatRotateVec3 | (out, q, v) => Vec3 | Rotate a vector by a quaternion. |
Projection helpers perspectiveZO, orthographicZO, lookAt, cameraPositionFromView and transformPoint live in @awaken/render (the camera module), not here.
screenRay
Picking and screen-space conversions, shared by the editor's tools and api.screenToWorld.
| Symbol | Signature | Description |
|---|---|---|
cssToNdc | (px, py, w, h) => { x, y } | Canvas CSS pixels (top-left origin) to normalized device coordinates. |
unprojectNdc | (view, proj, ndcX, ndcY) => { origin, dir } | World ray through an NDC point, unprojected at the near and far planes, so it is right for perspective and orthographic cameras alike. |
screenRay | (view, proj, px, py, w, h) => { origin, dir } | World ray through a canvas pixel. |
worldToCss | (view, proj, p, w, h) => { x, y } | null | Canvas pixel of a world point, or null behind the camera or outside the near..far range. |
entity
An Entity is a plain number that packs a 24-bit id with a generation counter (id + gen · 2²⁴), so it stays below 2⁴⁸ and remains an exact JS integer. The generation lets a freed id be reused without stale handles silently resolving to the new occupant.
| Symbol | Signature | Description |
|---|---|---|
Entity | number | Packed id + generation handle. |
NULL_ENTITY | Entity (0) | The "no entity" sentinel (also used for "no parent"). |
entityId | (e) => number | Extract the low 24-bit id. |
entityGen | (e) => number | Extract the generation. |
EntityAllocator | class | Allocates/frees entities; allocate(), free(e), isAlive(e). Owned by World. |
component
Components are data-only (no methods) and described by a reflection spec, so they serialize and appear in the Inspector without per-component code. defineComponent returns a ComponentType<T> that the World stores and the serializer walks.
| Symbol | Signature | Description |
|---|---|---|
FieldType | union | "number" | "bool" | "string" | "vec3" | "quat" | "vec4" | "color" | "enum" | "assetRef" | "entityRef" | "colliderShapes" | "scriptList" | "scriptParams" | "materialParams" | "entityRefMap" | "renderEffects" | "effectOverrides" | "clipMap". |
FieldSpec | { name; type; default; options?; … } | One field's reflection metadata. See the option list below. |
ComponentType<T> | { name; fields: FieldSpec[]; create: () => T; help? } | A registered component type. help is the text on the Inspector's ? marker. |
ComponentBase | { enabled?: boolean } | Base every component interface extends: the per-component enable toggle. |
ENABLED_FIELD | FieldSpec | The enabled field (type: "bool", default true) auto-appended to every component so it serializes; hidden from the Inspector body. |
defineComponent<T> | (name, fields, create, help?) => ComponentType<T> | Define a component; appends ENABLED_FIELD unless the list already has one. |
FieldSpec options. Only name, type, default and omitDefault affect what is saved; the rest are Inspector hints the serializer ignores.
| Option | Effect |
|---|---|
options | The values of an enum field. |
min, max, step, slider | Number bounds; slider: true renders a range control over [min, max]. |
omitDefault | Skip the field on save when it equals default, so adding a field does not rewrite every saved scene. |
mask: "renderLayers" | A number field holding a 32-bit layer mask shows the render-layer picker. |
showIf(values) | Hide the row when it returns false (a Collider's radius for a mesh shape). |
readOnly | Render the row disabled (runtime or derived values such as AnimStateMachine.state). |
hideWith | Hide the row when the entity also has the named component (Animator.clip hides under an AnimStateMachine). |
placement | The field places the object (position, rotation, a UI anchor). On a prefab instance's root it stays the instance's own: Apply never writes it into the prefab. |
help | The field's ? text. |
The enabled flag follows Unity's Behaviour.enabled: it is stored only when explicitly false, and systems skip a disabled component. See Component Reference for every registered type.
world
World is the ECS container: a sparse-set store per component type, a parent/child hierarchy, per-entity name/active/static/transient flags, one entity order, and change tracking for the renderer. Component lookups are by ComponentType, not string.
Entity lifecycle
| Method | Signature | Description |
|---|---|---|
createEntity | () => Entity | Allocate a new entity at the end of the world order. |
destroyEntity | (e) => void | Free an entity, detach it from the hierarchy, and remove all its components. |
isAlive | (e) => boolean | Whether the handle still refers to a live entity. |
clear | () => void | Remove every entity and component (resets the allocator) and bump clears. |
Components
| Method | Signature | Description |
|---|---|---|
add<T> | (e, type, init?) => T | Add a component (created from type.create(), overlaid with init). |
get<T> | (e, type) => T | undefined | Read a component. |
has | (e, type) => boolean | Whether the entity has the component. |
remove | (e, type) => void | Remove a component. |
entitiesWith | (type) => Entity[] | Every entity carrying type (a copy). |
view | (type) => readonly Entity[] | The store's live dense array: no allocation, but it changes under you when the component is added or removed. Never write to it. |
count | (type) => number | How many entities carry type, without registering the type. |
query | (...types) => Entity[] | Entities carrying all given types (iterates the smallest store). |
registry | Map<string, ComponentType> | Every component type the world has seen, keyed by name. |
Hierarchy, names, order & flags
| Method | Signature | Description |
|---|---|---|
setParent | (child, parent) => void | Reparent (NULL_ENTITY = detach). Rejects cycles. |
getParent | (e) => Entity | Parent, or NULL_ENTITY. |
getChildren | (e) => Entity[] | Direct children (a copy), in world order. |
getName / setName | (e) => string / (e, name) | Per-entity display name, kept in a name index. |
findNamed / findAllNamed | (name, type) => Entity | null / Entity[] | Entities with that name carrying type, in world order. Costs the number of entities with that name, not the scene size (api.find and the api.ui verbs use it). |
entityOrder | () => Entity[] | The world order: one sequence of every live entity. Loading a scene creates entities in this order, so save → load → save writes the same list. |
orderOf | (e) => number | A rank that only compares (lower = earlier); Infinity for a dead entity. |
setEntityOrder / moveInOrder | (order) / (e, ref, "before" | "after") | Rearrange the order (the Hierarchy's drags use these, undoably). moveInOrder moves e's whole subtree. |
isActive / setActive | (e) => boolean / (e, active) | This entity's own enable flag. |
isActiveInHierarchy | (e) => boolean | True only if the entity and every ancestor are active. |
isStatic / setStatic | (e) => boolean / (e, value) | The entity-level Static flag (non-moving scenery; drives batching + physics). See Static Batching. |
isTransient / setTransient | (e) => boolean / (e, value) | Generated, not authored (a streamed terrain chunk, a pooled object). serializeWorld skips transient entities, so a save writes the generator, not its output. Does not bump structureRev. |
Change tracking
| Member | Type | Description |
|---|---|---|
structureRev | number | Bumped on any structural change: entity create/destroy, component add/remove, active/static/parent change. Unchanged ⇒ the draw-cache topology is stable. Direct field writes (t.position) do not bump it. |
clears | number | Bumped by every clear(). A loaded scene reuses the previous scene's entity handles, so a cache keyed by handle compares this to know its scene is gone. |
markMoved | (e) => void | Flag an entity whose Transform a system/script changed this frame. |
movedEntities | ReadonlySet<Entity> | The set of flagged entities (read by the render loop). |
clearMoved | () => void | Clear the moved set (called once per frame by the sim owner). |
This is what makes a scene of 15k static props plus one rotator cost O(1) per frame instead of O(15k); see the render-frame performance notes.
transform
The Transform component (local position/rotation/scale) plus world-matrix computation.
| Symbol | Signature | Description |
|---|---|---|
Transform | ComponentType + interface | { position: Vec3; rotation: Quat; scale: Vec3 }. Defaults: pos 0, rot identity, scale 1. position and rotation are placement fields. |
worldTRS | (world, e) => { position, rotation, scale } | The entity's world TRS, composing every ancestor. Physics uses this so a nested collider lands on its mesh. |
computeWorldMatrices | (world) => Map<Entity, Mat4> | World matrix for every entity with a Transform (full recompute; cycle-guarded). |
updateWorldMatrices | (world, out, moved) => Entity[] | Incremental: recompute only the moved entities + descendants into out, reusing every other cached matrix. Returns the entities touched. |
A Transform-less ancestor breaks the chain (the entity roots there rather than composing past the gap); worldTRS and computeWorldMatrices agree on this so physics matches the render.
gameobject
A thin OO wrapper over World + Entity, mirroring Unity's GameObject. Everything it does is a World call underneath, so you can mix the two freely.
| Symbol | Signature | Description |
|---|---|---|
GameObject | class | Wraps (world, entity). name, transform, parent, children accessors + addComponent/getComponent/hasComponent/removeComponent. |
createGameObject | (world, name = "GameObject") => GameObject | Create an entity, name it, and give it a Transform. |
serialize
Scene ↔ JSON. SCENE_VERSION = 5 is the current scene-graph format; older scenes migrate forward on load. See Data Formats for the shape and the migration chain.
| Symbol | Signature | Description |
|---|---|---|
SCENE_VERSION | 5 | Current scene-graph format version. |
SceneJSON | { version; entities: EntityJSON[]; view2d?; nextPart? } | A serialized scene. view2d: true opens it in the 2D Scene view; nextPart is a prefab's next part id. Engine code reads neither. |
EntityJSON | { id; name; parent; active?; static?; components } | One serialized entity; active/static omitted at their defaults. |
worldEntities | (world, { transient? }) => Entity[] | The entities a save holds, in world order: every one with a component, minus transient ones unless asked. |
serializeWorld | (world) => SceneJSON | Serialize the world, skipping transient entities. |
serializeEntities | (world, entities, types?, ids?) => SceneJSON | Serialize an explicit list (copy/paste, prefab from selection); no transient filter. Parent links outside the set become null. |
instantiateScene | (world, json, types) => Entity[] | Add a scene's entities to a world (no clear); returns the new root entities. Migrates + clones object fields so instances never alias. |
instantiateSceneMapped | (world, json, types) => { roots, bySaveId } | The same, also returning which entity each save id became (prefab instances link their parts by id). |
applyComponentsJSON | (world, e, components, …) => void | Add or overwrite one entity's components from their saved form, remapping entity references. An unknown component name is skipped with a warning. |
applySceneToWorld | (world, json, types) => void | world.clear() then instantiateScene. |
deserializeWorld | (json, types) => World | Build a fresh World from a scene. |
migrateScene | (json) => SceneJSON | Forward-migrate a loaded scene to SCENE_VERSION (the one chokepoint every load passes through). |
applyMigrations | (json, migrations, current) => SceneJSON | Pure migration runner (injectable/testable). |
SCENE_MIGRATIONS | Record<number, SceneMigration> | The registered 1→2→3→4→5 steps (collider and multi-script format changes, then linked prefabs). |
instantiateScene runs in three passes (create entities, apply components while remapping entityRef/entityRefMap/scriptList handles, then wire the hierarchy) so references resolve regardless of entity order.
prefabLink
| Symbol | Shape | Description |
|---|---|---|
PrefabLink | ComponentType<{ prefab: string; part: number }> | Added by the editor to every object of a prefab instance: the prefab's name and the object's id in it. Engine code never reads it, and the player ignores it. See Prefabs. |
animation
A pure animation core with zero GPU dependency: skinning (clip + time → local pose → world bone matrices → skinning matrices → CPU-skinned positions), pose blending for crossfades, and root-motion sampling. The runtime's animationSystem wires it to the renderer.
| Symbol | Signature / Shape | Description |
|---|---|---|
Skeleton / Bone | { bones: Bone[] } / { name, parent, bind, inverseBind } | A bone hierarchy; parent is -1 for a root and parents precede children. |
AnimationClip | { name; duration; channels; rootMotion? } | A named clip. rootMotion is the baked horizontal pelvis X/Z per key, read by the animation system rather than applied to the pose. |
AnimationChannel / Keyframe | { bone, path, interp, keys } / { time, value } | One bone's translation, rotation or scale track. |
SkinData | { meshId; joints; weights; basePositions } | Per-vertex skin binding + read-only rest geometry for one skinned mesh. |
LocalPose | { t: Vec3[]; r: Quat[]; s: Vec3[] } | Per-bone local TRS for one sampled instant. |
Interp | "linear" | "step" | Keyframe interpolation (glTF cubicspline is sampled as linear). |
samplePose | (skel, clip, time, out?) => LocalPose | Sample a clip → per-bone local pose (undriven bones keep their bind pose). |
poseMatrices | (skel, pose, out?) => Mat4[] | Forward kinematics → per-bone world matrices. |
skinningMatrices | (skel, world, out?) => Mat4[] | world · inverseBind per bone (the matrices LBS multiplies by). |
skinPositions | (positions, joints, weights, skin, influences?) => Float32Array | Linear-blend-skin vertex positions on the CPU. |
blendPoses | (a, b, w, out?) => LocalPose | Per-bone slerp/lerp blend of two poses, the primitive behind clip crossfades. |
sampleRootMotion | (clip, time) => { x, z } | Sample the root-motion track (positions; subtract two samples for a delta). |
emptyPose / emptyMatrices | (n) => … | Preallocate out buffers so the per-frame path allocates nothing. |
vec3Lerp, quatSlerp, vec3LerpInto, quatSlerpInto, sampleVec3, sampleQuat | helpers | Interpolation and channel sampling; each Into form writes the caller's object. |
animGraph
The data model of the animation state machine. The runtime's AnimStateMachine component and animGraphSystem evaluate it.
| Symbol | Signature / Shape | Description |
|---|---|---|
AnimGraph | { name?; initial; states; transitions; params?; layout? } | A graph: its states, transitions, default parameter values and initial state. layout holds editor node positions and is ignored at runtime. |
AnimGraphState | { name; clip; loop?; speed?; start?; end? } | One state: a logical clip name and an optional play window. |
AnimTransition | { from; to; when: AnimCondition[]; fade? } | from: "*" fires from any state. |
AnimCondition / AnimOp | { param; op; value? } / ">" | ">=" | "<" | "<=" | "==" | "!=" | "trigger" | A declarative test on one parameter. |
conditionPasses / nextTransition / consumeTriggers / graphState | functions | Evaluate one condition; find the first firing transition; reset the one-shot triggers it used; look up a state. |
humanoid
The canonical humanoid slot map that rig profiles, retargeting, foot IK and the ragdoll resolve bones through.
| Symbol | Description |
|---|---|
HumanoidBodySlot / HUMANOID_BODY_SLOTS | 22 body slots, hips through rightToes. |
FingerSlot / FINGER_SLOTS | 30 finger slots, ${side}${finger}${phalanx} (for example leftIndexProximal). |
HumanoidSlot / HUMANOID_SLOTS | Body slots, then finger slots. |
HUMANOID_FINGERS, HUMANOID_PHALANGES, HumanoidSide | The parts the finger slot names are built from. |
midiOpts
| Symbol | Shape | Description |
|---|---|---|
MidiOpts | { tempo?; transpose?; instrument?; timbre?; reverb? } | How to perform a MIDI score. Stored on a sound asset by @awaken/assets, applied by @awaken/runtime; it lives in core because those two packages cannot import each other. |
GM_PROGRAMS | readonly string[] (128) | The General MIDI program names; MidiOpts.instrument indexes it. |
uiClip
| Symbol | Shape | Description |
|---|---|---|
UIClip | { name; duration; loop; tracks: UITrack[] } | A keyframe clip for UI elements, imported from Unity .anim. |
UITrack / UIKey | { target; prop; keys } / { t; v } | One property of one named element over time. |
UIProp | union | x, y, w, h, opacity, rotation, scaleX, scaleY, colorR, colorG, colorB. |
The runtime's UIAnimator plays these. See @awaken/runtime.
particles
The particle data model: the effect asset, the component, the gradient and curve samplers, and the GPU record shapes. The simulator is not here: EmitterState, makeEmitterState and simulateEmitter live in @awaken/runtime, because a per-frame integrator is a system rather than a model. See Particles.
| Symbol | Signature / Shape | Description |
|---|---|---|
ParticleEffect | config object | One effect's definition: emission (rate, bursts, maxParticles, duration, loop, oneShot, rateOverDistance), per-particle init (lifetime, shape, speed, spreadDeg and their variances), forces (gravity, drag, force, noise, drift), look over life (color gradient, sizeStart, sizeCurve, rotation), a flipbook grid (frameCols, frameRows, frameSpeed, frameLoop), render (blend, texture, worldSpace, softness, stretch, align, mesh), trail and subEmitters. |
EmissionShape | { kind: "point" } | { kind: "sphere"; radius } | { kind: "box"; half } | { kind: "cone"; angleDeg; radius } | Where particles spawn, in emitter-local space. |
ColorGradient / Curve | { stops: { t; color }[] } / { keys: { t; v }[] } | Colour and scalar over normalized lifetime (t 0→1, sorted), sampled on the CPU. |
ParticleEmitter | ComponentType<{ effect: string; playing: boolean }> | Places an effect on an entity. See Components. |
defaultEffect | () => ParticleEffect | A complete effect with every field at its default. |
particleRenderOpts | (cfg) => ParticleRenderOpts | The subset of an effect the renderer needs, derived in one place so scene emitters, one-shot bursts and the editor preview cannot disagree. |
sampleGradient / sampleGradientInto / sampleCurve | (g, t) / (out, g, t) / (c, t) | Linear sampling, t clamped to 0..1. |
PARTICLE_FLOATS | 16 | Per-particle GPU record: pos.xyz, size, rgba, rotation, vel.xyz, ageFrac, then 3 reserved lanes. |
TRAIL_POINT_FLOATS | 4 | Per trail point in the ribbon buffer: xyz + half-width. |
See also
- GameObjects & Components - the entity/component model in the editor.
- Transforms & Hierarchy - local vs world space and parenting.
- Component Reference - every registered component built with
defineComponent. - Data Formats & Versions - the
SceneJSONshape and migrations. - @awaken/render - the renderer that consumes
World+ world matrices.