Skip to content

@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.

SymbolSignatureDescription
Vec3{ x: number; y: number; z: number }3-component vector (plain object).
Quat{ x, y, z, w: number }Quaternion (plain object), w = 1 identity.
Mat4Float32Array (length 16)Column-major 4×4 matrix.
vec3(x?, y?, z?) => Vec3Construct a vector (defaults 0).
quat(x?, y?, z?, w?) => QuatConstruct a quaternion (defaults identity).
mat4() => Mat4A zeroed 16-float matrix.
snap(v, step) => numberRound v to the nearest multiple of step (step ≤ 0 → unchanged).
mat4Identity(out?) => Mat4Write the identity matrix.
mat4Multiply(out, a, b) => Mat4out = a · b (column-major).
mat4FromTRS(out, t, r, s) => Mat4Compose translation/rotation/scale into a matrix.
mat4Invert(out, m) => Mat4Invert m (identity fallback for a singular matrix).
mat4OrthoZO(out, l, r, b, t, near, far) => Mat4Orthographic projection, WebGPU clip space (z ∈ [0,1]).
mat4TransformPoint(out, m, p) => Vec3Apply a matrix to a point, dividing by w (or 1).
mat4TransformDir(out, m, v) => Vec3Upper 3×3 only: rotation and scale, no translation.
mat4TransformNormal(out, m, n) => Vec3Carry 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) => QuatEuler (XYZ, radians) → quaternion.
quatToEuler(q) => Vec3Quaternion → Euler angles (radians), inverse of quatFromEuler.
quatMultiply(out, a, b) => QuatQuaternion product.
quatFromAxisAngle(out, ax, ay, az, angle) => QuatRotation of angle radians about an axis.
quatFromTo(from, to) => QuatThe rotation turning from onto to (shared by foot IK and the ragdoll).
quatNormalize(out) => QuatNormalize in place (guards against drift).
quatRotateVec3(out, q, v) => Vec3Rotate 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.

SymbolSignatureDescription
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 } | nullCanvas 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.

SymbolSignatureDescription
EntitynumberPacked id + generation handle.
NULL_ENTITYEntity (0)The "no entity" sentinel (also used for "no parent").
entityId(e) => numberExtract the low 24-bit id.
entityGen(e) => numberExtract the generation.
EntityAllocatorclassAllocates/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.

SymbolSignatureDescription
FieldTypeunion"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_FIELDFieldSpecThe 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.

OptionEffect
optionsThe values of an enum field.
min, max, step, sliderNumber bounds; slider: true renders a range control over [min, max].
omitDefaultSkip 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).
readOnlyRender the row disabled (runtime or derived values such as AnimStateMachine.state).
hideWithHide the row when the entity also has the named component (Animator.clip hides under an AnimStateMachine).
placementThe 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.
helpThe 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 ​

MethodSignatureDescription
createEntity() => EntityAllocate a new entity at the end of the world order.
destroyEntity(e) => voidFree an entity, detach it from the hierarchy, and remove all its components.
isAlive(e) => booleanWhether the handle still refers to a live entity.
clear() => voidRemove every entity and component (resets the allocator) and bump clears.

Components ​

MethodSignatureDescription
add<T>(e, type, init?) => TAdd a component (created from type.create(), overlaid with init).
get<T>(e, type) => T | undefinedRead a component.
has(e, type) => booleanWhether the entity has the component.
remove(e, type) => voidRemove 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) => numberHow many entities carry type, without registering the type.
query(...types) => Entity[]Entities carrying all given types (iterates the smallest store).
registryMap<string, ComponentType>Every component type the world has seen, keyed by name.

Hierarchy, names, order & flags ​

MethodSignatureDescription
setParent(child, parent) => voidReparent (NULL_ENTITY = detach). Rejects cycles.
getParent(e) => EntityParent, 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) => numberA 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) => booleanTrue 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 ​

MemberTypeDescription
structureRevnumberBumped 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.
clearsnumberBumped 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) => voidFlag an entity whose Transform a system/script changed this frame.
movedEntitiesReadonlySet<Entity>The set of flagged entities (read by the render loop).
clearMoved() => voidClear 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.

SymbolSignatureDescription
TransformComponentType + 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.

SymbolSignatureDescription
GameObjectclassWraps (world, entity). name, transform, parent, children accessors + addComponent/getComponent/hasComponent/removeComponent.
createGameObject(world, name = "GameObject") => GameObjectCreate 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.

SymbolSignatureDescription
SCENE_VERSION5Current 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) => SceneJSONSerialize the world, skipping transient entities.
serializeEntities(world, entities, types?, ids?) => SceneJSONSerialize 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, …) => voidAdd 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) => voidworld.clear() then instantiateScene.
deserializeWorld(json, types) => WorldBuild a fresh World from a scene.
migrateScene(json) => SceneJSONForward-migrate a loaded scene to SCENE_VERSION (the one chokepoint every load passes through).
applyMigrations(json, migrations, current) => SceneJSONPure migration runner (injectable/testable).
SCENE_MIGRATIONSRecord<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.

SymbolShapeDescription
PrefabLinkComponentType<{ 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.

SymbolSignature / ShapeDescription
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?) => LocalPoseSample 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?) => Float32ArrayLinear-blend-skin vertex positions on the CPU.
blendPoses(a, b, w, out?) => LocalPosePer-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, sampleQuathelpersInterpolation 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.

SymbolSignature / ShapeDescription
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 / graphStatefunctionsEvaluate 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.

SymbolDescription
HumanoidBodySlot / HUMANOID_BODY_SLOTS22 body slots, hips through rightToes.
FingerSlot / FINGER_SLOTS30 finger slots, ${side}${finger}${phalanx} (for example leftIndexProximal).
HumanoidSlot / HUMANOID_SLOTSBody slots, then finger slots.
HUMANOID_FINGERS, HUMANOID_PHALANGES, HumanoidSideThe parts the finger slot names are built from.

midiOpts ​

SymbolShapeDescription
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_PROGRAMSreadonly string[] (128)The General MIDI program names; MidiOpts.instrument indexes it.

uiClip ​

SymbolShapeDescription
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.
UIPropunionx, 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.

SymbolSignature / ShapeDescription
ParticleEffectconfig objectOne 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.
ParticleEmitterComponentType<{ effect: string; playing: boolean }>Places an effect on an entity. See Components.
defaultEffect() => ParticleEffectA complete effect with every field at its default.
particleRenderOpts(cfg) => ParticleRenderOptsThe 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_FLOATS16Per-particle GPU record: pos.xyz, size, rgba, rotation, vel.xyz, ageFrac, then 3 reserved lanes.
TRAIL_POINT_FLOATS4Per trail point in the ribbon buffer: xyz + half-width.

See also ​

Awaken: browser-native WebGPU game engine.