AURA

JSGG

AuraJS
DOCSEXAMPLESGITHUB
09 Meshes, Materials, Scene3D, glTF, and Skinned Mesh
Mesh/material authoring, scene3d, glTF ingestion, and skinned mesh semantics.
docs/external/game-dev-api/09-meshes-materials-scene3d-gltf-and-skinned-mesh.md

Meshes, Materials, Scene3D, glTF, and Skinned Mesh

This page groups the 3D content and scene-management surfaces.

`aura.mesh`

Static/procedural mesh surface:

  • load(path)
  • createBox(width, height, depth)
  • createSphere(radius, segments?)
  • createPlane(width, depth)
  • createCylinder(radius, height, segments?)
  • createCone(radius, height, segments?)
  • createTorus(radius, tubeRadius, segments?)
  • createRing(innerRadius, outerRadius, segments?)
  • createExtrude(shape2d, optionsOrDepth?, segments?)
  • createLathe(points, optionsOrSegments?, phiStart?, phiLength?)
  • createFromVertices(vertices, indices, normals?, uvs?, colorsOrSkinning?, skinning?)
  • setMorphTargets(meshHandle, targets)
  • setMorphWeights(meshHandle, weights)
  • getData(meshHandle)
  • unload(meshHandle)

Generator guidance:

  • Use createRing, createExtrude, and createLathe for compact parametric props, blockouts, and proof slices where the authored shape is clearer in code than as an imported asset.
  • Prefer the options-object form for createExtrude(...) and createLathe(...) when you want the call site to carry explicit authored meaning for depth, segments, phiStart, and phiLength.
  • These generators throw on malformed authored input instead of fuzzily guessing. That is intentional contract behavior.
  • Prefer imported authored assets when the mesh needs complex organic topology, artist-owned asymmetry, or broader reuse outside code.

Skinned instance-group helpers currently also attach under aura.mesh:

  • createInstanceGroup(options)
  • instanceSetTransform(groupHandle, instanceId, transform)
  • instanceSetJointPose(groupHandle, instanceId, jointIndex, pose)
  • instanceSetJointMatrixRaw(groupHandle, instanceId, jointIndex, matrix)
  • destroyInstanceGroup(groupHandle)
  • getInstanceGroupInfo(groupHandle)

`aura.material`

Material surface:

  • create(options)
  • createCustom(options)
  • setColor(materialHandle, color)
  • setTexture(materialHandle, texturePath)
  • setNormalMap(materialHandle, input)
  • setMetallicRoughnessTexture(materialHandle, input)
  • setOcclusionTexture(materialHandle, input)
  • setEmissiveTexture(materialHandle, input)
  • setMetallic(materialHandle, metallic)
  • setRoughness(materialHandle, roughness)
  • setMetallicRoughness(materialHandle, metallic, roughness)
  • setBlendMode(materialHandle, mode)
  • setTextureTransform(materialHandle, options)
  • setEmissive(materialHandle, color, strength?)
  • setClearcoat(materialHandle, clearcoat, roughness?)
  • setRenderTargetTexture(materialHandle, input)
  • setCubeMapTexture(materialHandle, cubeCameraOrNull)
  • setRenderOrder(materialHandle, order)
  • setTransmission(materialHandle, value)
  • setAlphaCutoff(materialHandle, value)
  • setAlphaMode(materialHandle, mode)
  • setDoubleSided(materialHandle, enabled)
  • setSheen(materialHandle, roughness, color)
  • setSpecularFactor(materialHandle, value)
  • setSpecularColor(materialHandle, color)
  • setOcclusionStrength(materialHandle, value)
  • setIOR(materialHandle, value)
  • setThickness(materialHandle, value)
  • setShadingModel(materialHandle, model)
  • setToonSteps(materialHandle, value)
  • setToonEdge(materialHandle, value)
  • setIridescence(materialHandle, factor, ior?, thicknessMin?, thicknessMax?)
  • setAnisotropy(materialHandle, strength, rotation?)
  • setClippingPlanes(materialHandle, planes)
  • clearClippingPlanes(materialHandle)
  • setUniform(materialHandle, name, value)
  • setCustomTexture(materialHandle, texturePath)
  • setCustomTexture(materialHandle, slotNameOrIndex, texturePath)
  • setStencil(materialHandle, options)
  • clearStencil(materialHandle)
  • createGradientTexture(width, height, stops, options?)
  • createNoiseTexture(width, height, options?)
  • createDataTexture(width, height, pixelData, options?)
  • updateDataTexture(dataTextureHandle, pixelData)
  • destroyDataTexture(dataTextureHandle)
  • reset(materialHandle)
  • clone(materialHandle)
  • unload(materialHandle)

Current material-authoring truth:

  • advanced PBR knobs such as alphaCutoff, doubleSided, clearcoat, sheenColor, sheenRoughness, specularFactor, and specularColor are already available at material creation time
  • runtime setter parity now also covers setAlphaCutoff, setAlphaMode, setDoubleSided, setSheen, setSpecularFactor, setSpecularColor, setOcclusionStrength, and the secondary texture setters setNormalMap, setMetallicRoughnessTexture, setOcclusionTexture, and setEmissiveTexture
  • secondary texture setters accept either a string asset path, a DataTextureHandle, or null; the current non-albedo data-texture path is a snapshot-at-bind seam rather than a live-linked material slot
  • material-side procedural texture authoring now also includes two CPU-backed helpers over the same queue: createGradientTexture(...) for authored color ramps and createNoiseTexture(...) for deterministic seeded white noise
  • setCubeMapTexture(...) now ships one bounded per-material live cubemap consumer over the existing cube-camera lane; it accepts a cube camera handle (or { handle }) and null to fall back to the shared scene IBL source
  • the current cubemap override stays intentionally narrow: it is a cube-camera source override for the main forward-material consumer path, not a generalized reflection graph or skinned/capture-path parity claim
  • this does not imply GPU-backed texture synthesis or a baking pipeline; the helper layer still ends in the same CreateDataTexture submission seam
  • some advanced knobs still remain create-time only, including the texture-backed sheen/specular lanes and broader subsurface-style material breadth
  • treat data textures, texture transforms, and stencil as shipped material-side surfaces today rather than future-work rumors

Reflection Probe Ownership

Stage 195 adds one thin authored helper on top of the existing cube-camera and material-consumer floor:

  • aura.draw3d.createReflectionProbe(options?)
  • aura.draw3d.updateReflectionProbe(probe, patch?)
  • aura.draw3d.destroyReflectionProbe(probe)

Accepted authored inputs stay intentionally narrow:

  • position?: Vec3
  • near?: number
  • far?: number
  • resolution?: number
  • facesPerFrame?: number
  • materials?: MaterialHandle[]
  • useAsEnvironmentMap?: boolean

Truthful ownership:

  • one reflection probe owns one cube-camera capture source
  • it may bind that owned cubemap to one or more authored material handles
  • it may optionally set the shared scene environment map from the same owned probe
  • updateReflectionProbe(...) is the retained refresh/mutation seam for probe position, capture settings, material bindings, and the optional shared environment assignment

This helper is not a universal reflection graph. In particular, it does not imply:

  • automatic probe placement or blending
  • arbitrary cubemap sources beyond the owned probe capture
  • skinned-mesh, postfx, or other broader capture-path parity beyond the underlying cube-camera floor
  • automatic reflections on every reflective material in the scene

Use setCubeMapTexture(...) directly when the game wants to own cube cameras and material bindings separately. Use reflection probes when the game wants one authored owner for that bounded capture-plus-binding workflow.

Canonical bounded proof:

  • examples/neon-district/src/city.js uses the chrome sculpture as one reflective hero object with reflection-probe ownership first and the older cube-camera floor as the fallback path.

Custom-shader guidance:

  • createCustom(options) is a narrow advanced seam, not the default material path. Use it when standard PBR material controls cannot express the effect you need.
  • uniforms declares only scalar/vector/matrix data. Texture access is declared separately with texture: true for one legacy slot or textures: ['base', 'accent'] for named multi-slot contracts, then mutated later with setCustomTexture(...).
  • setUniform(...) and setCustomTexture(...) return stable structured failure reasons on contract errors such as unknown uniforms, invalid uniform values, or missing texture declaration.
  • Bad WGSL can still fail later on the native compile path even after a handle is returned. Treat the public proof slices and conformance cases as the truth surface for what is actually frozen.

Reusable shader-kit guidance:

  • AuraJS now also ships a plain-JS shader-kit layer at @auraindustry/aurajs/shader-kits for reusable authored presets over this same custom-material seam.
  • Current shipped presets are:
    • hologram / fresnel
    • dissolve
    • foliage / wind
    • rim / emissive accent
  • These kits are convenience wrappers over createCustom(...), setUniform(...), and setCustomTexture(...). They are not a shader graph, material editor, or a broader renderer abstraction.

`aura.scene3d`

Hierarchy and transform helpers

  • createNode(initialTransform?)
  • removeNode(nodeId)
  • setParent(nodeId, parentId)
  • getParent(nodeId)
  • setLocalTransform(nodeId, transform)
  • getLocalTransform(nodeId)
  • getWorldTransform(nodeId)
  • traverse(rootNodeId, callback)

Interaction query helpers

  • screenToRay(pixelX, pixelY)
  • pick(pixelX, pixelY, options?)
  • queryRaycast(originOrOptions, maybeDirection?, maybeOptions?)
  • setDrawMeshQueryTag(meshHandle, tagOrNull)
  • raycast(origin, direction, options?)

Current query truth:

  • queryRaycast(...) and pick(...) operate on retained scene3d nodes and return authored node identity such as nodeId, plus current render-binding identity like layer, meshHandle, materialHandle, visible, and hasRenderBinding
  • queryRaycast(...) supports retained-scene filters such as firstOnly, visibleOnly, requireRenderBinding, layerMask, includeNodeIds, and excludeNodeIds
  • setDrawMeshQueryTag(...) stores one authored string tag per submitted draw-mesh handle; pass null to clear the authored tag
  • raycast(...) is the submitted draw-mesh lane; it returns mesh hits, optional triangle hits, and the authored queryTag, but not retained scene3d node identity
  • use physics3d.queryRaycast(...) instead when the query must follow physics bodies and physics-world filters rather than retained scene/render identity

Render binding and culling helpers

  • bindRenderNode(nodeId, meshHandle, materialHandle, options?)
  • unbindRenderNode(nodeId)
  • setNodeVisibility(nodeId, visible)
  • setNodeLayer(nodeId, layer)
  • setNodeCulling(nodeId, enabled, options?)
  • setNodeLod(nodeId, lodSpec)
  • clearNodeLod(nodeId)
  • getNodeLod(nodeId)
  • getLodState()
  • setCameraLayerMask(mask)
  • setCullBounds(bounds)
  • clearCullBounds()
  • submitRenderBindings(options?)
  • getRenderSubmissionState()

glTF import helpers

Current import-related surface spans both metadata helpers and normalized import-record helpers:

  • loadGltfScene(path, options?)
  • unloadGltfScene(importId)
  • getImportedScene(importId)
  • getImportedSceneMetadata(importId)
  • getImportedCameras(importId)
  • getImportedLights(importId)
  • getImportedAnimations(importId)
  • playImportedAnimation(importId, animationName, options?)

Current native importer notes:

  • .gltf external buffer files resolve relative to the source asset path.
  • Sparse animation accessors are supported in the native import path.
  • Invalid external URI schemes or malformed sparse payloads fail with stable import reason codes.

Clip and crossfade helpers

  • createClip(options)
  • playClip(clipId)
  • pauseClip(clipId)
  • resumeClip(clipId)
  • seekClip(clipId, time)
  • setClipWeight(clipId, weight)
  • setClipLoop(clipId, loop)
  • setClipSkinning(clipId, options)
  • crossfadeClips(fromClipId, toClipId, options)
  • updateClips(dt)
  • onClipEvent(clipId, callback, order?)
  • getClipState(clipId)

Avatar runtime helpers

  • createAvatar(options)
  • updateAvatars(dt, avatars?)

The current avatar runtime sits on top of scene3d imported-scene bindings, clip playback, and character3d. The returned avatar object exposes:

  • spawn(spawnOptions?)
  • destroy()
  • setInput(input)
  • jump(velocity?)
  • setVisual(options) / bindModel(options)
  • setAnimations(animations, options?)
  • setAnimationState(options)
  • defineSocket(name, options?)
  • attach(socketName, sceneNodeId, options?)
  • detach(socketName)
  • getSockets()
  • onAnimationEvent(callback)
  • playAnimation(clipKeyOrEntry, options?)
  • getAvailableAnimations()
  • clearAnimation()
  • setPosition(position)
  • getRenderTransform()
  • getState()
  • tick(dtSeconds)

Practical imported-avatar path:

const imported = aura.scene3d.loadGltfScene('examples/starter-templates/3d/assets/models/starter-avatar.gltf', {
  bindRenderNodes: true,
  visible: true,
  cull: false,
});

const avatar = aura.scene3d.createAvatar({
  spawn: false,
  sceneNodeId: imported.nodeHandles[0].nodeId,
  importId: imported.importId,
  animations: {
    idle: 'Idle',
    walk: 'Walk',
    run: 'Run',
    jump: 'Jump',
    fall: 'Fall',
  },
  camera: {
    offset: { x: 0, y: 2.7, z: -6.8 },
    lookOffset: { x: 0, y: 0.72, z: 0 },
    rotateWithFacing: true,
  },
});

avatar.spawn();
avatar.setInput({ moveX: 1, run: true });
avatar.tick(dt);
aura.scene3d.submitRenderBindings();

Honest boundary:

  • the current proof asset is the shipped starter-avatar.gltf fixture
  • it is a compact committed transform-rigged avatar, not a production skinned hero asset
  • use aura.skinnedMesh when you need direct skeleton/joint ownership rather than the higher-level imported-avatar runtime path

`aura.skinnedMesh`

Dedicated skinned-mesh namespace:

  • create(options)
  • setJointTransforms(handle, transforms)
  • playAnimation(handle, clipName, options?)
  • stopAnimation(handle)
  • blendAnimations(handle, fromClip, toClip, options?)
  • getJointPosition(handle, jointNameOrIndex)
  • addClip(handle, clipSpec)

Practical split of responsibilities

Use these namespaces this way:

  • aura.mesh: create/load mesh assets and procedural geometry
  • aura.material: create and mutate materials
  • aura.scene3d: node hierarchy, imported-scene metadata, render binding, raycasts, clips, avatar runtime
  • aura.skinnedMesh: dedicated skinned character helpers
  • aura.draw3d: actual draw submission
DOCUMENT REFERENCE
docs/external/game-dev-api/09-meshes-materials-scene3d-gltf-and-skinned-mesh.md
AURAJS
Cmd/Ctrl+K
aurajsgg