Skip to main content

ANARI C API and THREE.js Mapping

ExperimentalPrivate workspaceFrom-v10

This page maps the official ANARI 1.1 specification to the experimental, private @luma.gl/anari implementation and, where helpful, to comparable THREE.js concepts.

The first column is the authoritative ANARI C vocabulary. The JavaScript column describes what this package actually implements, not what a fully conformant ANARI binding would need to implement. The THREE.js column is a conceptual migration aid, not an adapter or dependency.

caution

@luma.gl/anari is not a binding to the ANARI C API, is not ABI-compatible with ANARI, and does not claim ANARI conformance. Some mappings are approximate, some are convenience extensions, and many official functions are not implemented.

High-level mental model

Rendering conceptOfficial ANARI C@luma.gl/anariComparable THREE.js concept
Rendering implementationANARILibrary + ANARIDeviceExisting luma.gl Device wrapped by ANARIDeviceWebGPURenderer or WebGLRenderer
Scene rootANARIWorldANARIWorldScene
Geometry dataANARIGeometry + ANARIArrayANARIGeometry + ANARIArrayBufferGeometry, geometry subclasses, BufferAttribute
Surface appearanceANARIMaterialANARIMaterialMeshStandardMaterial, MeshPhysicalMaterial, or other material
Geometry + materialANARISurfaceANARISurfaceMesh
Reusable collectionANARIGroupANARIGroupGroup
Transformed placementANARIInstanceANARIInstanceObject3D.matrix, Object3D.matrixWorld, or an InstancedMesh transform
LightANARILightANARILightAmbientLight, DirectionalLight, PointLight, SpotLight
ViewANARICameraANARICameraPerspectiveCamera or OrthographicCamera
Rendering policyANARIRendererANARIRendererRenderer plus material, tone-mapping, and postprocessing configuration
Render operationANARIFrame + anariRenderFrame()ANARIFrame.render()renderer.render(scene, camera)

THREE.js generally exposes a mutable, renderer-owned object graph. ANARI explicitly separates a device, retained parameters, committed scene objects, a renderer description, and frame operations. The two systems solve overlapping problems but do not have identical ownership or lifecycle semantics.

Library and device functions

ANARI 1.1 C API@luma.gl/anariTHREE.js comparisonStatus and differences
anariLoadLibrary()No equivalentImport three/webgpu or threeJavaScript modules are imported normally; no ANARI implementation library is dynamically loaded.
anariUnloadLibrary()No equivalentNo direct equivalentModule loading and process lifetime are managed by the JavaScript runtime.
anariNewDevice()new ANARIDevice(graphicsDevice)new WebGPURenderer() / new WebGLRenderer()Wraps an already-created luma.gl device instead of creating an ANARI library-backed device.
anariNewInitializedDevice()Configure luma.createDevice(...), then new ANARIDevice(graphicsDevice)Renderer constructor optionsComparable initialization step, but no ANARI initializer array or device subtype selection.
anariGetDeviceSubtypes()No equivalentRenderer class / backend selectionBackend selection happens through luma.gl adapter ordering, not ANARI device-library discovery.
anariGetDeviceExtensions()anariDevice.extensionsCapability inspection on the selected rendererReturns this proof of concept's static extension-name list; no library/subtype-specific extension query.
ANARIStatusCallbackNo equivalentApplication logging / error handlingNo ANARI severity, status-code, callback, or callback-user-data interface.
const graphicsDevice = await luma.createDevice({
adapters: [webgpuAdapter, webgl2Adapter],
createCanvasContext: true
});

const anariDevice = new ANARIDevice(graphicsDevice);

The native concept “select an ANARI device implementation” therefore maps to “select a luma.gl graphics backend, then wrap it,” not to loading a Khronos-compatible ANARI device.

Object creation functions

ANARI 1.1 C API@luma.gl/anariComparable THREE.js conceptSupport
anariNewArray1D(device, memory, deleter, userData, elementType, count)anariDevice.newArray({data, elementType, dimensions})Typed array + BufferAttributePartial: one-dimensional typed arrays and object-reference arrays; no deleter callback or ownership transfer.
anariNewArray2D()No equivalentDataTexture, texture image dataNot implemented.
anariNewArray3D()No equivalentData3DTextureNot implemented.
anariNewGeometry(device, subtype)anariDevice.newGeometry(subtype, parameters)BufferGeometry or a geometry subclassSupported for triangle, sphere, cylinder, cone, and quad; primitive semantics are simplified.
anariNewMaterial(device, subtype)anariDevice.newMaterial(subtype, parameters)MeshStandardMaterial / MeshPhysicalMaterialSupported for matte and physicallyBased; many official material parameters are absent.
anariNewSurface(device)anariDevice.newSurface({geometry, material})new Mesh(geometry, material)Supported; references are supplied in the factory call.
anariNewGroup(device)anariDevice.newGroup({surface, light})new Group()Supported for surface/light collections.
anariNewInstance(device, subtype)anariDevice.newInstance({group, transform})Object3D transform or InstancedMesh.setMatrixAt()Supported only for transform instances.
anariNewWorld(device)anariDevice.newWorld({surface, instance, light})new Scene()Supported for direct surfaces, instances, and lights.
anariNewLight(device, subtype)anariDevice.newLight(subtype, parameters)THREE.js light subclassesSupported for directional, point, and spot; JavaScript additionally provides an ambient convenience subtype.
anariNewCamera(device, subtype)anariDevice.newCamera(subtype, parameters)PerspectiveCamera / OrthographicCameraSupported for perspective and orthographic.
anariNewRenderer(device, subtype)anariDevice.newRenderer(subtype, parameters)Renderer configuration / debug materialSupported for default, WebGPU-only deferred and raytrace, debugNormals, debugDepth, and locally registered renderer runtimes.
anariNewFrame(device)anariDevice.newFrame({world, camera, renderer, size})renderer.render(scene, camera) / render targetSupported for canvas presentation; arbitrary mapped output channels are not implemented.
anariNewSampler()anariDevice.newSampler('image2D', {image, transform})Texture, sampler state, texture-backed material propertiesPartial: retained 2D image samplers; no procedural or volume samplers.
anariNewSpatialField()No equivalent3D texture / volume fieldNot implemented.
anariNewVolume()No equivalentVolume renderer / 3D textureNot implemented.
anariNewObject()new ANARIObject(...) exists; renderer runtimes register separatelyCustom Object3D subclassNo generic extension-object registration; custom renderer runtimes use anariDevice.registerRenderer().

Important primitive differences

Official ANARI sphere, cylinder, cone, and quad geometries can represent collections of primitives described by arrays such as vertex.position, per-primitive indices, and radii. This implementation creates one procedural engine geometry from scalar parameters such as radius, height, width, and segments.

For example:

anariDevice.newGeometry('sphere', {radius: 1, segments: 32});

is conceptually closer to new THREE.SphereGeometry(1, ...) than to the full official ANARI sphere-soup data model. Use retained instances to place that procedural sphere repeatedly.

Official ANARI light subtypes include directional, point, spot, HDRI, quad, and ring lights. The JavaScript ambient light is a convenience extension; the standard expresses ambient illumination as renderer configuration such as ambientRadiance, rather than defining the same ambient light subtype.

Parameter and commit functions

ANARI 1.1 C API@luma.gl/anariTHREE.js comparisonSupport and differences
anariSetParameter(device, object, name, dataType, value)object.setParameter(name, value)Assign mesh.material.roughness = valueSupported conceptually. TypeScript and JavaScript values replace explicit ANARIDataType and C pointers.
Repeated anariSetParameter(...) callsobject.setParameters({...})Assign several object/material propertiesJavaScript convenience for staging multiple parameters.
anariUnsetParameter(device, object, name)object.unsetParameter(name)Reset/delete a property, depending on the objectSupported; still requires commitParameters().
anariUnsetAllParameters()No equivalentReplace/reset object configurationNot implemented.
anariCommitParameters(device, object)object.commitParameters()Property updates, material.needsUpdate, attribute.needsUpdate, or updateMatrix()Supported; staged changes become visible only after committing.
Read back a parameterobject.getParameter(name) / object.getParameters()Read ordinary JavaScript object propertiesJavaScript-only extension: official ANARI deliberately does not provide a general parameter-readback API.

C versus JavaScript example

float roughness = 0.15f;
anariSetParameter(device, material, "roughness", ANARI_FLOAT32, &roughness);
anariCommitParameters(device, material);
material.setParameter('roughness', 0.15).commitParameters();

The commit boundary is intentionally similar. The parameter typing and ownership models are not: official ANARI passes an explicit data type and a pointer, while the JavaScript package uses typed method signatures and ordinary values.

Commit versus THREE.js updates

// @luma.gl/anari
material.setParameter('roughness', 0.15).commitParameters();

// Conceptual THREE.js equivalent
threeMaterial.roughness = 0.15;

THREE.js materials are generally mutated directly. Some operations additionally require explicit flags such as material.needsUpdate, attribute.needsUpdate, or instancedMesh.instanceMatrix.needsUpdate; those are GPU-update hints, not an ANARI-style transactional commit mechanism.

Arrays and mapped memory

ANARI 1.1 C API@luma.gl/anariTHREE.js comparisonSupport
anariNewArray1D()newArray({data})new BufferAttribute(typedArray, itemSize)Zero-copy JavaScript typed-array storage; no C deleter or reference-count contract.
anariMapArray()Access array.data directlyAccess attribute.arrayNo explicit map call; retained typed-array data remains directly accessible.
anariUnmapArray()No equivalentattribute.needsUpdate = trueNo explicit map/unmap synchronization. Commit the owning geometry after changing rendered array data.
anariMapParameterArray1D()No equivalentAllocate/update an attribute arrayNot implemented.
anariMapParameterArray2D()No equivalentUpdate texture image dataNot implemented.
anariMapParameterArray3D()No equivalentUpdate 3D texture dataNot implemented.
anariUnmapParameterArray()No equivalentattribute.needsUpdate / texture.needsUpdateNot implemented.
ANARIDeleterCallbackNo equivalentJavaScript garbage collection / explicit GPU dispose()No application-memory deleter callback or transferred memory ownership.
const positions = new Float32Array([-1, 0, 0, 1, 0, 0, 0, 1, 0]);
const array = anariDevice.newArray({data: positions, elementType: 'float32x3'});

positions[0] = -2;
geometry.commitParameters();

The array retains the original JavaScript object. array.length counts scalar JavaScript elements; new Float32Array(9) reports 9, not three vec3 elements.

Discovery, properties, and extensions

ANARI 1.1 C API@luma.gl/anariTHREE.js comparisonSupport
anariGetObjectSubtypes(device, objectType)anariDevice.getObjectSubtypes(type)Select known constructors / inspect renderer capabilitiesSupported with JavaScript string object types.
anariGetObjectInfo(device, objectType, subtype, infoName, infoType)anariDevice.getObjectInfo(type)Class/capability inspectionPartial: returns {type, subtypes, extensions} only, not arbitrary named metadata.
anariGetParameterInfo()No equivalentConstructor documentation / TypeScript typesNot implemented; parameter schemas are documented and statically typed rather than introspectable at runtime.
anariGetProperty()No generic equivalent; use frame.statisticsRenderer/scene properties and renderer infoPartial only: render statistics are exposed directly, but ANARI property queries and wait masks are absent.
anariGetDeviceExtensions()anariDevice.extensionsRenderer/backend capability propertiesStatic package extension list rather than library-dependent/runtime-dependent discovery.
anariDevice.getObjectSubtypes('geometry');
// ['triangle', 'sphere', 'cylinder', 'cone', 'quad']

anariDevice.getObjectInfo('material');
// {type: 'material', subtypes: [...], extensions: [...]}

The current extension names describe concepts the proof of concept supports; they are not evidence of complete, certified Khronos extension behavior.

Frame rendering and presentation

ANARI 1.1 C API@luma.gl/anariTHREE.js comparisonSupport and differences
anariRenderFrame(device, frame)frame.render() or anariDevice.renderFrame(frame)renderer.render(scene, camera)Supported conceptually, but the JavaScript call immediately encodes/draws instead of exposing official asynchronous frame-operation semantics.
anariFrameReady(device, frame, waitMask)No equivalentNo exact equivalentNot implemented; there is no polling/wait-mask frame API.
anariDiscardFrame()No equivalentStop an application animation loopNot implemented; no in-flight frame cancellation API.
anariMapFrame(device, frame, channel, ...)No equivalentRender target / pixel readbackNot implemented; frames present to the canvas and do not expose mapped pixel channels.
anariUnmapFrame()No equivalentRelease a mapped/readback resourceNot implemented.
ANARIFrameCompletionCallbackNo equivalentAnimation loop / promise integrationNot implemented.
Frame channel.color, channel.depth, channel.normal, and other channelsNo equivalentRender targets, depth textures, G-buffersNot implemented as ANARI channels. debugNormals and debugDepth are visualization renderers, not mappable output channels.
const statistics = frame.render();
graphicsDevice.submit();

Official ANARI rendering is specified as asynchronous and may support readiness queries, cancellation, frame channels, mapping, and completion callbacks. The JavaScript proof of concept returns rendering statistics immediately while GPU execution still follows the underlying luma.gl device's command/submission behavior.

Retention and destruction

ANARI 1.1 C API@luma.gl/anariTHREE.js comparisonSupport
anariRetain()No equivalentKeep a JavaScript object referenceJavaScript object references replace explicit native handle retention.
anariRelease() on a scene objectNo equivalentgeometry.dispose() / material.dispose()No general per-object reference-count or release method.
anariRelease() on a frameframe.destroy()Dispose render targets / postprocessing resourcesReleases frame-owned GPU resources, but is not a general ANARI handle-release operation.
anariRelease() on a deviceanariDevice.destroy()renderer.dispose()Releases ANARI runtime resources; does not destroy the separately owned luma.gl Device.
frame.destroy();
anariDevice.destroy();
graphicsDevice.destroy();

Only destroy the graphics device when the application no longer shares it with other rendering or compute systems.

Geometry subtype comparison

Official ANARI subtype@luma.gl/anariComparable THREE.js classImportant difference
trianglenewGeometry('triangle', {...})BufferGeometry + position/normal/tangent/UV/color/skin/index attributesSupports positions, normals, XYZW tangents, RGB/RGBA colors, two UV sets, joint indices/weights, position/normal/tangent morph targets, and 16/32-bit indices; not the complete official attribute system.
spherenewGeometry('sphere', {radius, segments})SphereGeometryOne procedural sphere; official ANARI supports arrays of sphere primitives.
cylindernewGeometry('cylinder', {radius, height, segments})CylinderGeometryOne capped procedural cylinder; official ANARI supports collections of indexed cylinder primitives.
conenewGeometry('cone', {radius, height, segments})ConeGeometryOne capped procedural cone; official ANARI supports arrays of cone primitives.
quadnewGeometry('quad', {width, height})PlaneGeometryOne XZ-plane procedural quad; official ANARI quad geometry supports explicit vertex/index arrays.
curveNot supportedLine, LineSegments, tube/curve geometryNot implemented.
isosurfaceNot supportedCustom marching-cubes / isosurface implementationNot implemented.

Material parameter comparison

Official ANARI concept@luma.gl/anariComparable THREE.js propertyNotes
matte.colormaterial.color / baseColor / baseColorTexturematerial.color / mapConstant RGB/RGBA values optionally multiplied by a retained image map.
physicallyBased.baseColorbaseColor / baseColorTextureMeshStandardMaterial.color / mapConstant color multiplied by an optional image sampler.
metallicmetallic, metallicRoughnessTextureMeshStandardMaterial.metalness / metalnessMapScalar metallic factor and the source map's blue channel.
roughnessroughness, metallicRoughnessTextureMeshStandardMaterial.roughness / roughnessMapScalar roughness factor and the source map's green channel.
opacityopacity, alphaMode, alphaCutoffmaterial.opacity + material.transparent / alphaTestCommitted structural changes rebuild the shared blend/mask rendering pipeline.
alphaModeopaque, mask, and blend; alphaCutoff supportedtransparent, alphaTestCommitted changes select the appropriate shared rendering pipeline.
emissiveemissive, emissiveTextureMeshStandardMaterial.emissive / emissiveMapConstant emissive RGB optionally multiplied by an image map.
Emissive scalingemissiveStrengthMeshStandardMaterial.emissiveIntensityJavaScript convenience scalar.
clearcoatclearcoat, clearcoatRoughness, clearcoatTexture, clearcoatRoughnessTexture, clearcoatNormalTextureMeshPhysicalMaterial.clearcoat / clearcoat mapsShared clearcoat term supports authored factor, roughness, and tangent-space normal maps.
iridescenceiridescence, iridescenceTexture, iridescenceThicknessTextureMeshPhysicalMaterial.iridescence / iridescence mapsShared angle-dependent thin-film approximation with authored factor and thickness maps.
Normal, roughness, metallic, and base-color samplersnormalTexture, metallicRoughnessTexture, baseColorTextureMaterial textures/mapsRetained image2D samplers support independent transforms and either primary or secondary UVs.
Transmission, index of refraction, and volume attenuationtransmission, transmissionTexture, thickness, thicknessTexture, attenuationColor, attenuationDistance, indexOfRefractionMeshPhysicalMaterial.transmission / thickness / attenuationShared renderer captures opaque scene color for screen-space refraction; it is not layered ray tracing.
Sheen and anisotropysheenColor, sheenRoughness, sheenColorTexture, sheenRoughnessTexture, anisotropyStrength, anisotropyRotation, anisotropyTextureMeshPhysicalMaterial.sheen / anisotropy and associated mapsAuthored factors and maps are supported through the existing shared shader approximations.

Light and camera comparison

Official ANARI concept@luma.gl/anariComparable THREE.js class/propertyNotes
Directional lightnewLight('directional', {direction, irradiance})DirectionalLightDirection and intensity map conceptually; shadow behavior is absent.
Point lightnewLight('point', {position, intensity})PointLightFixed attenuation; no official radius/power behavior.
Spot lightnewLight('spot', {position, direction, openingAngle, falloffAngle})SpotLight.angle / SpotLight.penumbraopeningAngle sets the outer cone; falloffAngle sets the inner cone.
Renderer ambient lightingrenderer.ambientRadianceAmbientLight or environment lightingThis aligns more closely with the official renderer ambient-light extension.
Ambient light objectnewLight('ambient', ...)AmbientLightJavaScript convenience; not an official ANARI 1.1 light subtype.
HDRI / quad / ring area lightsNot supportedEnvironment maps / area lightsNot implemented.
Perspective cameranewCamera('perspective', {fovy, ...})PerspectiveCameraANARI-style fovy is expressed in radians; THREE.js constructor fov uses degrees.
Orthographic cameranewCamera('orthographic', {height, ...})OrthographicCameraJavaScript derives horizontal extent from height * aspect.
Camera depth of field, motion blur, stereo, panoramic projectionsNot supportedSpecialized camera / postprocessing featuresNot implemented.

THREE.js migration example

The following snippets express approximately the same simple scene. They are not interchangeable implementations.

THREE.js

import * as THREE from 'three';

const scene = new THREE.Scene();
const geometry = new THREE.SphereGeometry(1, 48, 24);
const material = new THREE.MeshPhysicalMaterial({
color: 0x3388ff,
metalness: 0.85,
roughness: 0.18,
clearcoat: 0.25
});

const mesh = new THREE.Mesh(geometry, material);
mesh.position.set(0, 1, 0);
scene.add(mesh);

const light = new THREE.PointLight(0xff8833, 30);
light.position.set(3, 2, 0);
scene.add(light);

const camera = new THREE.PerspectiveCamera(50, width / height, 0.05, 200);
camera.position.set(0, 2, 8);
camera.lookAt(0, 1, 0);

renderer.render(scene, camera);

@luma.gl/anari

const geometry = anariDevice.newGeometry('sphere', {radius: 1, segments: 24});
const material = anariDevice.newMaterial('physicallyBased', {
baseColor: [0.2, 0.53, 1],
metallic: 0.85,
roughness: 0.18,
clearcoat: 0.25
});

const surface = anariDevice.newSurface({geometry, material});
const group = anariDevice.newGroup({surface: [surface]});
const instance = anariDevice.newInstance({
group,
transform: new Matrix4().translate([0, 1, 0])
});

const light = anariDevice.newLight('point', {
position: [3, 2, 0],
color: [1, 0.53, 0.2],
intensity: 30
});

const world = anariDevice.newWorld({instance: [instance], light: [light]});
const camera = anariDevice.newCamera('perspective', {
position: [0, 2, 8],
direction: [0, -1, -8],
fovy: 50 * Math.PI / 180
});
const renderer = anariDevice.newRenderer('default');
const frame = anariDevice.newFrame({world, camera, renderer, size: [width, height]});

frame.render();

THREE.js-specific differences

  • THREE.js attaches transforms directly to Object3D; ANARI separates surfaces, groups, and transform instances.
  • THREE.js does not require a general explicit parameter commit; ANARI-style updates require commitParameters().
  • THREE.js InstancedMesh is constructed explicitly and requires instance-matrix updates; this package derives instanced draws from shared ANARISurface identities.
  • THREE.js MeshStandardMaterial.metalness corresponds conceptually to ANARI metallic, not to a property named metalness in this package.
  • THREE.js camera field of view is commonly specified in degrees; ANARI fovy here is specified in radians.
  • THREE.js provides many mature features absent from this proof of concept, including extensive texture/material systems, shadow maps, loaders, raycasting, postprocessing, and broad scenegraph functionality.
  • THREE.js WebGPURenderer can fall back to WebGL 2; this package obtains similar portability by configuring luma.gl WebGPU and WebGL adapters explicitly.

Official sources