1"use strict";(self.webpackChunkgenies_devkit_docs=self.webpackChunkgenies_devkit_docs||[]).push([[1676],{3905:(e,t,a)=>{a.d(t,{Zo:()=>s,kt:()=>u});var n=a(67294);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function i(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function l(e){for(var t=1;t<arguments.length;t++){var a=null!=arguments[t]?arguments[t]:{};t%2?i(Object(a),!0).forEach((function(t){r(e,t,a[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(a)):i(Object(a)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(a,t))}))}return e}function o(e,t){if(null==e)return{};var a,n,r=function(e,t){if(null==e)return{};var a,n,r={},i=Object.keys(e);for(n=0;n<i.length;n++)a=i[n],t.indexOf(a)>=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)a=i[n],t.indexOf(a)>=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var d=n.createContext({}),p=function(e){var t=n.useContext(d),a=t;return e&&(a="function"==typeof e?e(t):l(l({},t),e)),a},s=function(e){var t=p(e.components);return n.createElement(d.Provider,{value:t},e.children)},m="mdxType",k={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},N=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,i=e.originalType,d=e.parentName,s=o(e,["components","mdxType","originalType","parentName"]),m=p(a),N=r,u=m["".concat(d,".").concat(N)]||m[N]||k[N]||i;return a?n.createElement(u,l(l({ref:t},s),{},{components:a})):n.createElement(u,l({ref:t},s))}));function u(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=a.length,l=new Array(i);l[0]=N;var o={};for(var d in t)hasOwnProperty.call(t,d)&&(o[d]=t[d]);o.originalType=e,o[m]="string"==typeof e?e:r,l[1]=o;for(var p=2;p<i;p++)l[p]=a[p];return n.createElement.apply(null,l)}return n.createElement.apply(null,a)}N.displayName="MDXCreateElement"},65972:(e,t,a)=>{a.r(t),a.d(t,{assets:()=>d,contentTitle:()=>l,default:()=>k,frontMatter:()=>i,metadata:()=>o,toc:()=>p});var n=a(87462),r=(a(67294),a(3905));const i={},l="API Summary",o={unversionedId:"sdk-web/api/summary",id:"sdk-web/api/summary",title:"API Summary",description:"This page summarizes the public API exposed by the Genies Web SDK, organized by area. Named exports are canonical \u2014 initialize() also returns a NafInstance containing the most common APIs.",source:"@site/docs/sdk-web/api/summary.md",sourceDirName:"sdk-web/api",slug:"/sdk-web/api/summary",permalink:"/docs/sdk-web/api/summary",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"webSidebar",previous:{title:"Quick Start Examples",permalink:"/docs/sdk-web/getting-started/quick-start"},next:{title:"Troubleshooting",permalink:"/docs/sdk-web/tools/troubleshooting"}},d={},p=[{value:"What is NAF?",id:"what-is-naf",level:2},{value:"Quick start",id:"quick-start",level:2},{value:"Choose a loading API",id:"choose-a-loading-api",level:3},{value:"Avatar Definition",id:"avatar-definition",level:3},{value:"Initialization and runtime",id:"initialization-and-runtime",level:2},{value:"<code>initialize(options?)</code>",id:"initializeoptions",level:3},{value:"Runtime APIs",id:"runtime-apis",level:3},{value:"Authentication and services",id:"authentication-and-services",level:3},{value:"Avatars and wearables",id:"avatars-and-wearables",level:2},{value:"Loading",id:"loading",level:3},{value:"<code>NafAvatarHandle</code>",id:"nafavatarhandle",level:3},{value:"<code>NafWearableHandle</code>",id:"nafwearablehandle",level:3},{value:"Animation and behavior",id:"animation-and-behavior",level:2},{value:"Top-level APIs",id:"top-level-apis",level:3},{value:"<code>AvatarAnimationController</code>
1",id:"avataranimationcontroller",level:3},{value:"Dynamics, IK, and body motion",id:"dynamics-ik-and-body-motion",level:3},{value:"Managed rendering",id:"managed-rendering",level:2},{value:"Materials and shaders",id:"materials-and-shaders",level:2},{value:"Built-in effects",id:"built-in-effects",level:3},{value:"Presets are JSON",id:"presets-are-json",level:3},{value:"Preset layers and asset scopes",id:"preset-layers-and-asset-scopes",level:3},{value:"RGBK colors",id:"rgbk-colors",level:3},{value:"Assets and cache",id:"assets-and-cache",level:2},{value:"Voice helpers",id:"voice-helpers",level:2},{value:"Events",id:"events",level:2},{value:"Event error phases",id:"event-error-phases",level:3},{value:"Logging and diagnostics",id:"logging-and-diagnostics",level:2},{value:"Advanced integrations",id:"advanced-integrations",level:2},{value:"Content authoring tools",id:"content-authoring-tools",level:2},{value:"Browser-safe tools",id:"browser-safe-tools",level:3},{value:"Node tools",id:"node-tools",level:3}],s={toc:p},m="wrapper";function k(e){let{components:t,...a}=e;return(0,r.kt)(m,(0,n.Z)({},s,a,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"api-summary"},"API Summary"),(0,r.kt)("p",null,"This page summarizes the public API exposed by the Genies Web SDK, organized by area. Named exports are canonical \u2014 ",(0,r.kt)("inlineCode",{parentName:"p"},"initialize()")," also returns a ",(0,r.kt)("inlineCode",{parentName:"p"},"NafInstance")," containing the most common APIs."),(0,r.kt)("h2",{id:"what-is-naf"},"What is NAF?"),(0,r.kt)("p",null,"NAF (",(0,r.kt)("strong",{parentName:"p"},"Native Avatar Framework"),") is a WebGL SDK for loading, animating, and rendering Genies avatars in the browser. It wraps a C++ animation engine compiled to WebAssembly (via Emscripten) and exposes a clean JavaScript API on top of Three.js."),(0,r.kt)("admonition",{title:"Source of truth",type:"info"},(0,r.kt)("p",{parentName:"admonition"},"TypeScript definitions ship with the package and are the source of truth for exact types, overloads, and optional fields \u2014 your editor resolves them automatically from ",(0,r.kt)("inlineCode",{parentName:"p"},"@geniesinc/genies-naf-webgl"),". This page focuses on consumer-facing APIs; some lower-level runtime hooks exist in the package for tooling and custom integrations, but are not part of the recommended app integration surface.")),(0,r.kt)("h2",{id:"quick-start"},"Quick start"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"import { initialize } from '@geniesinc/genies-naf-webgl';\n\nconst naf = await initialize({\n canvas,\n initScene: () => ({ renderer, scene, camera }),\n environment: 'prod',\n bearerToken: token,\n});\n\nconst avatar = await naf.loadAvatarProgressive(avatarSource, {\n renderer,\n scene,\n lod: [2, 0],\n idle: { id: 'idle_neutral', version: '1' },\n});\n\nfunction frame(deltaTime) {\n avatar.controller?.update(deltaTime);\n avatar.controller?.syncPose();\n naf.update(deltaTime);\n}\n\n// Releases native, Three.js, animation, shader, and LOD resources.\navatar.unload();\n")),(0,r.kt)("h3",{id:"choose-a-loading-api"},"Choose a loading API"),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Goal"),(0,r.kt)("th",{parentName:"tr",align:null},"API"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Load an avatar at one LOD"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"loadAvatar(source, options)"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Load silhouette, progressive LODs, animation, and behavior"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"loadAvatarProgressive(source, options)"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Load a wearable without an avatar"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"loadWearable(id, options)"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Warm the complete avatar cache"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"preloadAssets(source, lods?)"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Warm individual assets"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"prefetchAsset(...)")," / ",(0,r.kt)("inlineCode",{parentName:"td"},"prefetchAssets(...)"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Build a custom rendering integration"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"advanced.rendering"))))),(0,r.kt)("p",null,"A ",(0,r.kt)("inlineCode",{parentName:"p"},"source")," is either an ",(0,r.kt)("strong",{parentName:"p"},"avatar definition")," or a ",(0,r.kt)("strong",{parentName:"p"},"CAMP avatar ID")," such as ",(0,r.kt)("inlineCode",{parentName:"p"},"bm_avatar_*"),". CAMP (",(0,r.kt)("strong",{parentName:"p"},"Content and Asset Management Platform"),") is the collection of Genies backend services and infrastru
1cture. Pass a CAMP ID and the SDK resolves the underlying assets for you. A ",(0,r.kt)("inlineCode",{parentName:"p"},"bm_smart-avatar_*")," ID must first be passed to ",(0,r.kt)("inlineCode",{parentName:"p"},"resolveSmartAvatar()")," \u2014 then load the ",(0,r.kt)("inlineCode",{parentName:"p"},"avatarId")," it returns."),(0,r.kt)("admonition",{title:"CAMP ID prefixes",type:"note"},(0,r.kt)("p",{parentName:"admonition"},"CAMP avatars, wearables, animations, smart avatars, and behaviors support ",(0,r.kt)("inlineCode",{parentName:"p"},"bm_"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"vm_"),", and ",(0,r.kt)("inlineCode",{parentName:"p"},"um_")," prefixes. The ",(0,r.kt)("inlineCode",{parentName:"p"},"bm_")," examples on this page also accept the other prefixes. Always pass the full ID unchanged \u2014 prefixes are part of asset identity, not interchangeable aliases.")),(0,r.kt)("h3",{id:"avatar-definition"},"Avatar Definition"),(0,r.kt)("p",null,"Avatar definitions are JSONs that describe an avatar's assets:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json"},'{\n "assets": [\n { "id": "asset-abc-123", "version": "1" },\n { "id": "asset-def-456", "version": "1" }\n ],\n "shapeAttributes": { ... }\n}\n')),(0,r.kt)("hr",null),(0,r.kt)("h2",{id:"initialization-and-runtime"},"Initialization and runtime"),(0,r.kt)("h3",{id:"initializeoptions"},(0,r.kt)("inlineCode",{parentName:"h3"},"initialize(options?)")),(0,r.kt)("p",null,"Initializes WASM, the virtual filesystem, resolver configuration, texture configuration, authentication, and the managed rendering frontend. It is idempotent and returns a ",(0,r.kt)("inlineCode",{parentName:"p"},"Promise<NafInstance>"),"."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Option"),(0,r.kt)("th",{parentName:"tr",align:null},"Purpose"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"canvas")),(0,r.kt)("td",{parentName:"tr",align:null},"Existing canvas. The SDK creates one when omitted.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"width"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"height")),(0,r.kt)("td",{parentName:"tr",align:null},"Size of an SDK-created canvas.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"initScene(canvas, gl)")),(0,r.kt)("td",{parentName:"tr",align:null},"Return ",(0,r.kt)("inlineCode",{parentName:"td"},"{ renderer, scene, camera?, render? }")," to register the Web render host.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"environment")),(0,r.kt)("td",{parentName:"tr",align:null},"Asset environment: ",(0,r.kt)("inlineCode",{parentName:"td"},"'dev'")," or ",(0,r.kt)("inlineCode",{parentName:"td"},"'prod'"),".")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"bearerToken")),(0,r.kt)("td",{parentName:"tr",align:null},"Global native REST bearer token. Empty enables native authentication fallback.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"services")),(0,r.kt)("td",{parentName:"tr",align:null},"Per-service ",(0,r.kt)("inlineCode",{parentName:"td"},"{ baseUrl?, bearerToken?, sdkVersion? }")," overrides.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"assetResolverConfigPath")),(0,r.kt)("td",{parentName:"tr",align:null},"Custom resolver configuration URL.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"textureSettingsPath")),(0,r.kt)("td",{parentName:"tr",align:null},"Custom texture settings URL.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"maxSupportedPipelineVersion")),(0,r.kt)("td",{parentName:"tr",align:null},"Highest supported asset pipeline version.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"managedRenderFrontend")),(0,r.kt)("td",{parentName:"tr",align:null},"Defaults to ",(0,r.kt)("inlineCode",{parentName:"td"},"true"),". Set ",(0,r.kt)("inlineCode",{parentName:"td"},"false")," only for a consumer-owned renderer.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"WebGL context options"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"alpha"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"antialias"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"depth"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"stencil"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"preserveDrawingBuffer"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"powerPreference"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"premultipliedAlpha"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"desynchronized"),".")))),(0,r.kt)("h3",{id:"runtime-apis"},"Runtime APIs"),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"API"),(0,r.kt)("th",{parentName:"tr",align:null},"Purpose"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"update(deltaTime)")),(0,r.kt)("td",{parentName:"tr",align:null},"Process native frame state, texture uploads, managed rendering, and first-frame work. Call once per frame.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"getCanvas()")," / ",(0,r.kt)("inlineCode",{parentName:"td"},"getContext()")),(0,r.kt)("td",{parentName:"tr",align:null},"Return the SDK canvas and WebGL2 context.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"setWasmBasePath(path)")),(0,r.kt)("td",{parentName:"tr",align:null},"Override the auto-detected WASM asset path before initialization.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"setEnvironment(env)")," / ",(0,r.kt)("inlineCode",{parentName:"td"},"getEnvironment()")),(0,r.kt)("td",{parentName:"tr",align:null},"Change or read the resolver environment.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"BUILD_CONFIG")),(0,r.kt)("td",{parentName:"tr",align:null},"Read ",(0,r.kt)("inlineCode",{parentName:"td"},"{ buildType, isDebug, isRelease }"),".")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"NafInstance")),(0,r.kt)("td",{parentName:"tr",align:null},"Convenience facade returned by ",(0,r.kt)("inlineCode",{parentName:"td"},"initialize()"),". Named exports remain canonical.")))),(0,r.kt)("admonition",{title:"Changed in v0.1.96",type:"caution"},(0,r.kt)("p",{parentName:"admonition"},(0,r.kt)("inlineCode",{parentName:"p"},"update(deltaTime)")," no longer accepts a renderer \u2014 managed WebGL state reset and frame submission now happen internally. Drop the second argument when upgrading.")),(0,r.kt)("h3",{id:"authentication-and-services"},"Authentication and services"),(0,r.kt)("p",null,"The SDK supports two authentication modes:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"External auth")," \u2014 you manage the token and hand it to the SDK."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"Native auth")," \u2014 the SDK manages everything automatically (used when the token is empty).")),(0,r.kt)("p",null,"Prefer configuring auth at startup via ",(0,r.kt)("inlineCode",{parentName:"p"},"initialize({ bearerToken, services })"),". The setters below are intended for ",(0,r.kt)("strong",{parentName:"p"},"runtime")," changes, such as a token refresh."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"API"),(0,r.kt)("th",{parentName:"tr",align:null},"Purpose"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"setBearerToken(token)")),(0,r.kt)("td",{parentName:"tr",align:null},"Set the global native REST token.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"setServiceBaseUrl(service, url)")),(0,r.kt)("td",{parentName:"tr",align:null},"Override a service endpoint; an empty URL clears it.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"setServiceBearerToken(service, token)")),(0,r.kt)("td",{parentName:"tr",align:null},"Override a service token; ",(0,r.kt)("inlineCode",{parentName:"td"},"null")," or empty clears it.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"setServiceSdkVersion(service, version)")),(0,r.kt)("td",{parentName:"tr",align:null},"Override a service compatibility version; empty restores its configuration default.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"startNativeSseStream(options)")),(0,r.kt)("td",{parentName:"tr",align:null},"Open a native-owned SSE stream. Returns ",(0,r.kt)("inlineCode",{parentName:"td"},"{ stop(), state() }"),", or ",(0,r.kt)("inlineCode",{parentName:"td"},"null")," if RTC bindings are unavailable.")))),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"import { setBearerToken } from '@geniesinc/genies-naf-webgl';\n\n// Update when your token refreshes\nonTokenRefresh((newToken) => {\n setBearerToken(newToken);\n});\n\n// Clear to switch back to native auth\nsetBearerToken('');\n")),(0,r.kt)("admonition",{title:"CAMP service version",type:"note"},(0,r.kt)("p",{parentName:"admonition"},"Set ",(0,r.kt)("inlineCode",{parentName:"p"},"services.camp.sdkVersion")," to select the CAMP compatibility version for avatar, wearable, animation, smart-avatar, and behavior requests. An explicit per-request ",(0,r.kt)("inlineCode",{parentName:"p"},"sdkVersion")," takes precedence without changing that default; otherwise native service configuration supplies the version. This is the ",(0,r.kt)("em",{parentName:"p"},"service")," compatibility version \u2014 independent of the installed Web SDK package version.")),(0,r.kt)("hr",null),(0,r.kt)("h2",{id:"avatars-and-wearables"},"Avatars and wearables"),(0,r.kt)("h3",{id:"loading"},"Loading"),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"API"),(0,r.kt)("th",{parentName:"tr",align:null},"Result"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"loadAvatar(source, options)")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"Promise<NafAvatarHandle>")," at one LOD.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"loadAvatarProgressive(source, options)")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"Promise<NafAvatarHandle>")," with optional silhouette, LOD progression, animation, and behavior.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"loadWearable(id, options)")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"Promise<NafWearableHandle>")," for a ",(0,r.kt)("strong",{parentName:"td"},"CAMP")," wearable. CAMP IDs are ",(0,r.kt)("em",{parentName:"td"},"self-versioned")," \u2014 the version is part of the ID, so you don't pass one.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"loadWearable(id, version, options)")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"Promise<NafWearableHandle>")," for a ",(0,r.kt)("strong",{parentName:"td"},"legacy (pre-CAMP)")," wearable, where the version is a separate argument.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"getLoadedAvatars()")),(0,r.kt)("td",{parentName:"tr",align:null},"Avatar handles currently registered by the runtime. Check ",(0,r.kt)("inlineCode",{parentName:"td"},"isReady")," before driving one. Unloaded handles are removed.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"pickAvatar(raycaster, options?)")),(0,r.kt)("td",{parentName:"tr",align:null},"Closest ready avatar intersection, or ",(0,r.kt)("inlineCode",{parentName:"td"},"null"),".")))),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Common load options:")),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Option"),(0,r.kt)("th",{parentName:"tr",align:null},"Purpose"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"renderer")),(0,r.kt)("td",{parentName:"tr",align:null},"Required ",(0,r.kt)("inlineCode",{parentName:"td"},"THREE.WebGLRenderer"),".")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"lod")),(0,r.kt)("td",{parentName:"tr",align:null},"One LOD for ",(0,r.kt)("inlineCode",{parentName:"td"},"loadAvatar"),"; an order such as ",(0,r.kt)("inlineCode",{parentName:"td"},"[2, 0]")," for progressive loading.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"meshOptions")),(0,r.kt)("td",{parentName:"tr",align:null},"Mesh construction options.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"proceduralTextures")),(0,r.kt)("td",{parentName:"tr",align:null},"Procedural textures are generated on the GPU as the avatar loads. Defaults to ",(0,r.kt)("inlineCode",{parentName:"td"},"true"),"; disable to use supported authored fallbacks.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"dynamics")),(0,r.kt)("td",{parentName:"tr",align:null},"Embedded dynamics by default, an override, or ",(0,r.kt)("inlineCode",{parentName:"td"},"false")," to disable.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"signal")),(0,r.kt)("td",{parentName:"tr",align:null},"Cancels stale loads and suppresses late publication.")))),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Progressive-only options:")),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Option"),(0,r.kt)("th",{parentName:"tr",align:null},"Purpose"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"scene")),(0,r.kt)("td",{parentName:"tr",align:null},"Lets the SDK add/remove silhouette and final meshes without a visual gap.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"position"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"rotation")),(0,r.kt)("td",{parentName:"tr",align:null},"Initial transform shared by silhouette and final avatar.")),(0,r.kt)("tr",{pare
1ntName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"idle")),(0,r.kt)("td",{parentName:"tr",align:null},"The looping idle animation the avatar plays when it isn't doing anything else, given as ",(0,r.kt)("inlineCode",{parentName:"td"},"{ id, version? }")," \u2014 ",(0,r.kt)("inlineCode",{parentName:"td"},"id")," is the animation asset's identifier and ",(0,r.kt)("inlineCode",{parentName:"td"},"version")," is only needed for legacy IDs. Providing it creates and configures the animation controller for you.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"behavior")),(0,r.kt)("td",{parentName:"tr",align:null},"Smart-avatar behavior \u2014 the configuration that decides which idle, gesture, and talking clips play and when. Requires animation. See the field table below.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"syncOptions")),(0,r.kt)("td",{parentName:"tr",align:null},"Skeleton, blendshape, and coordinate-conversion synchronization options.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"onSilhouette"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"onReady"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"onLodUpgrade"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"onError")),(0,r.kt)("td",{parentName:"tr",align:null},"Per-load callbacks. The ",(0,r.kt)("em",{parentName:"td"},"silhouette")," is a fast, low-detail stand-in mesh shown while the full-quality avatar streams in, so there's no empty space on screen \u2014 ",(0,r.kt)("inlineCode",{parentName:"td"},"onSilhouette")," fires when it's ready. ",(0,r.kt)("inlineCode",{parentName:"td"},"onReady")," fires after animation setup but before the final mesh is added to the scene, and is awaited, which makes it the right place to apply shaders and presets.")))),(0,r.kt)("admonition",{type:"note"},(0,r.kt)("p",{parentName:"admonition"},"Native cache resolution may skip requested lower-quality LODs. The ",(0,r.kt)("inlineCode",{parentName:"p"},"avatar:ready")," event reports the actual starting LOD as ",(0,r.kt)("inlineCode",{parentName:"p"},"initialLod"),".")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"The ",(0,r.kt)("inlineCode",{parentName:"strong"},"behavior")," object:")),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Field"),(0,r.kt)("th",{parentName:"tr",align:null},"Purpose"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"config")),(0,r.kt)("td",{parentName:"tr",align:null},"A behavior configuration you already have in hand, as an object or JSON string. Using it skips the network fetch.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"behaviorId")),(0,r.kt)("td",{parentName:"tr",align:null},"A CAMP behavior-config ID (",(0,r.kt)("inlineCode",{parentName:"td"},"bm_behavior-config_*"),") for the SDK to fetch.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"slug")),(0,r.kt)("td",{parentName:"tr",align:null},"The legacy (pre-CAMP) way to identify a behavior for fetching.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"talking")),(0,r.kt)("td",{parentName:"tr",align:null},"Animation asset ID used for the talking motion.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"breathing")),(0,r.kt)("td",{parentName:"tr",align:null},"Animation asset ID used for the breathing motion.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"emotion")),(0,r.kt)("td",{parentName:"tr",align:null},"Default emotion clip, used when the behavior's demeanor doesn't specify one.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"onLoaded")),(0,r.kt)("td",{parentName:"tr",align:null},"Fires once the behavior and all its clips have finished loading.")))),(0,r.kt)("p",null,"If more than one source is supplied, precedence is ",(0,r.kt)("inlineCode",{parentName:"p"},"config")," first, then ",(0,r.kt)("inlineCode",{parentName:"p"},"behaviorId"),", then ",(0,r.kt)("inlineCode",{parentName:"p"},"slug"),"."),(0,r.kt)("h3",{id:"nafavatarhandle"},(0,r.kt)("inlineCode",{parentName:"h3"},"NafAvatarHandle")),(0,r.kt)("p",null,"The handle owns the complete avatar lifecycle. Its ",(0,r.kt)("inlineCode",{parentName:"p"},"mesh")," identity remains stable across supported updates."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Member"),(0,r.kt)("th",{parentName:"tr",align:null},"Purpose"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"avatarId"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"mesh"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"controller")),(0,r.kt)("td",{parentName:"tr",align:null},"Runtime identity, Three.js group, and optional animation controller.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"status"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"isReady"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"isUnloaded")),(0,r.kt)("td",{parentName:"tr",align:null},"Lifecycle state. Do not drive a handle before ",(0,r.kt)("inlineCode",{parentName:"td"},"isReady"),".")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"currentLod")),(0,r.kt)("td",{parentName:"tr",align:null},"LOD currently rendered, or ",(0,r.kt)("inlineCode",{parentName:"td"},"null"),".")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"proceduralTexturesEnabled")),(0,r.kt)("td",{parentName:"tr",align:null},"Effective procedural texture mode.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"userData")),(0,r.kt)("td",{parentName:"tr",align:null},"A free-form object for your own metadata. The SDK never reads or writes it, so you can attach whatever your app needs (a database key, UI state) and it travels with the handle.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"getEquippedAssets()")),(0,r.kt)("td",{parentName:"tr",align:null},"Assets retained after native composition rules.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"getSourceShaderPreset()")),(0,r.kt)("td",{parentName:"tr",align:null},"Independent copy of the base Mega Stylizer preset plus current asset presets under ",(0,r.kt)("inlineCode",{parentName:"td"},"multiAsset"),", or ",(0,r.kt)("inlineCode",{parentName:"td"},"null"),".")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"getExtensionNames()")," / ",(0,r.kt)("inlineCode",{parentName:"td"},"getExtensionJson(name)")),(0,r.kt)("td",{parentName:"tr",align:null},"Inspect the JSON ",(0,r.kt)("em",{parentName:"td"},"extensions")," baked into the avatar's assets \u2014 extra authored data attached to the asset, such as ",(0,r.kt)("inlineCode",{parentName:"td"},"GENIES_dynamics")," (physics setup) or ",(0,r.kt)("inlineCode",{parentName:"td"}
1,"GENIES_rig_recipe")," (skeleton setup). ",(0,r.kt)("inlineCode",{parentName:"td"},"getExtensionNames()")," lists which are present; ",(0,r.kt)("inlineCode",{parentName:"td"},"getExtensionJson(name)")," returns one as a JSON string.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"equipAsset(...)")," / ",(0,r.kt)("inlineCode",{parentName:"td"},"unequipAsset(id)")),(0,r.kt)("td",{parentName:"tr",align:null},"Add or remove a wearable and publish the resulting update.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"replaceAssets(ids, replacement...)")),(0,r.kt)("td",{parentName:"tr",align:null},"Atomically remove and optionally replace assets.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"setColor(id, color, options?)")," / ",(0,r.kt)("inlineCode",{parentName:"td"},"unsetColor(...)")),(0,r.kt)("td",{parentName:"tr",align:null},"Apply or remove native runtime color overrides.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"getColorAttributes()")),(0,r.kt)("td",{parentName:"tr",align:null},"Return global and per-asset color IDs.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"configureDynamics(...)")),(0,r.kt)("td",{parentName:"tr",align:null},"Re-resolve the effective dynamics source.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"setDynamicsOverride(...)")," / ",(0,r.kt)("inlineCode",{parentName:"td"},"clearDynamicsOverride()")),(0,r.kt)("td",{parentName:"tr",align:null},"Apply or clear a local dynamics override.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"getDynamicsState()")),(0,r.kt)("td",{parentName:"tr",align:null},"Return ",(0,r.kt)("inlineCode",{parentName:"td"},"{ source, active, error, overrideError }"),".")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"getRefitReport()")," / ",(0,r.kt)("inlineCode",{parentName:"td"},"getAnchorReport()")),(0,r.kt)("td",{parentName:"tr",align:null},"Refit and anchoring diagnostics.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"getSkeletonRootCorrectionReport()")),(0,r.kt)("td",{parentName:"tr",align:null},"Report inverse-bind-matrix root correction.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"getUtilityMeshData()")),(0,r.kt)("td",{parentName:"tr",align:null},"Return copied utility mesh geometry for tooling.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"unload()")),(0,r.kt)("td",{parentName:"tr",align:null},"Idempotently release all resources owned by the handle.")))),(0,r.kt)("admonition",{title:"Ordering",type:"note"},(0,r.kt)("p",{parentName:"admonition"},"Equip, unequip, and replace mutations are serialized per handle. Await each operation when order matters, since remote resolution can finish out of order. Progressive wearable upgrades replace only the affected render data and keep animation state continuous.")),(0,r.kt)("p",null,"Refitting and layering run during native composition using the asset's authored rest-cage and/or anchor bindings \u2014 they do not require a separate JavaScript call. Use ",(0,r.kt)("inlineCode",{parentName:"p"},"getRefitReport()")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"getAnchorReport()")," to inspect the active composition."),(0,r.kt)("h3",{id:"nafwearablehandle"},(0,r.kt)("inlineCode",{parentName:"h3"},"NafWearableHandle")),(0,r.kt)("p",null,"Standalone wearables let you load and mutate a wearable ",(0,r.kt)("strong",{parentName:"p"},"without")," a full avatar. They expose a stable ",(0,r.kt)("inlineCode",{parentName:"p"},"mesh"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"renderId"),", lifecycle state, ",(0,r.kt)("inlineCode",{parentName:"p"},"userData"),", asset mutation, runtime color, ",(0,r.kt)("inlineCode",{parentName:"p"},"getSourceShaderPreset()"),", and ",(0,r.kt)("inlineCode",{parentName:"p"},"unload()"),". Source presets use the same stable asset scopes as avatars."),(0,r.kt)("p",null,"Standalone wearables do not have an avatar skeleton, animation controller, dynamics, or base-rig restriction."),(0,r.kt)("hr",null),(0,r.kt)("h2",{id:"animation-and-behavior"},"Animation and behavior"),(0,r.kt)("h3",{id:"top-level-apis"},"Top-level APIs"),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"API"),(0,r.kt)("th",{parentName:"tr",align:null},"Purpose"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"attachAnimation(handle, options?)")),(0,r.kt)("td",{parentName:"tr",align:null},"Create an ",(0,r.kt)("inlineCode",{parentName:"td"},"AvatarAnimationController"),", attach it to the handle, and apply dynamics.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"loadAnimation(id, version?)")),(0,r.kt)("td",{parentName:"tr",align:null},"Load a legacy resolver animation or CAMP ",(0,r.kt)("inlineCode",{parentName:"td"},"bm_anim-asset_*")," clip as a ",(0,r.kt)("inlineCode",{parentName:"td"},"Uint8Array"),"; returns ",(0,r.kt)("inlineCode",{parentName:"td"},"null")," when unavailable.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"categorizeClips(names)")),(0,r.kt)("td",{parentName:"tr",align:null},"Split names into ",(0,r.kt)("inlineCode",{parentName:"td"},"{ idleClips, gestureClips }"),".")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"activateBehavior(controller, options?)")),(0,r.kt)("td",{parentName:"tr",align:null},"Activate behavior from ",(0,r.kt)("inlineCode",{parentName:"td"},"config"),", CAMP ",(0,r.kt)("inlineCode",{parentName:"td"},"behaviorId"),", or legacy ",(0,r.kt)("inlineCode",{parentName:"td"},"slug"),". Returns ",(0,r.kt)("inlineCode",{parentName:"td"},"Promise<boolean>"),".")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"resolveSmartAvatar(id, options?)")),(0,r.kt)("td",{parentName:"tr",align:null},"Resolve ",(0,r.kt)("inlineCode",{parentName:"td"},"bm_smart-avatar_*")," to ",(0,r.kt)("inlineCode",{parentName:"td"},"id"),", ",(0,r.kt)("inlineCode",{parentName:"td"}
1,"displayName"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"avatarId"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"behaviorId"),", and expanded ",(0,r.kt)("inlineCode",{parentName:"td"},"avatar"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"behavior"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"brain"),", and ",(0,r.kt)("inlineCode",{parentName:"td"},"voice")," objects.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"resolveBehavior(id, options?)")),(0,r.kt)("td",{parentName:"tr",align:null},"Resolve ",(0,r.kt)("inlineCode",{parentName:"td"},"bm_behavior-config_*")," to an editable config accepted by ",(0,r.kt)("inlineCode",{parentName:"td"},"activateBehavior"),".")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"AvatarAnimationController")),(0,r.kt)("td",{parentName:"tr",align:null},"Public controller class used by the high-level loaders.")))),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"activateBehavior")," accepts ",(0,r.kt)("inlineCode",{parentName:"p"},"config"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"behaviorId"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"slug"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"talking"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"breathing"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"emotion"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"transferIdleTimeFrom"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"onLoaded"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"avatarId"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"signal"),", and ",(0,r.kt)("inlineCode",{parentName:"p"},"isCurrent"),". Source precedence is ",(0,r.kt)("inlineCode",{parentName:"p"},"config"),", then ",(0,r.kt)("inlineCode",{parentName:"p"},"behaviorId"),", then ",(0,r.kt)("inlineCode",{parentName:"p"},"slug"),". CAMP resolution uses the configured CAMP service credentials and rejects HTTP or invalid-content failures. Both resolve APIs accept an optional ",(0,r.kt)("inlineCode",{parentName:"p"},"sdkVersion"),". The same behavior options work with ",(0,r.kt)("inlineCode",{parentName:"p"},"loadAvatarProgressive"),", including after equip/unequip rebuilds."),(0,r.kt)("admonition",{title:"Knowing when behavior is really loaded",type:"note"},(0,r.kt)("p",{parentName:"admonition"},"Use ",(0,r.kt)("inlineCode",{parentName:"p"},"onLoaded")," or the ",(0,r.kt)("inlineCode",{parentName:"p"},"avatar:behavior-loaded")," event to observe native behavior loading completion \u2014 the activation result alone does not signal that all clips are loaded.")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Working with CAMP smart avatars:")," resolve the smart-avatar ID first, pass its ",(0,r.kt)("inlineCode",{parentName:"p"},"avatarId")," to ",(0,r.kt)("inlineCode",{parentName:"p"},"loadAvatarProgressive"),", and set ",(0,r.kt)("inlineCode",{parentName:"p"},"behavior: { behaviorId: resolved.behaviorId }"),". Brain and voice data are returned for ",(0,r.kt)("strong",{parentName:"p"},"inspection only")," \u2014 they are not automatically activated. An unassigned brain or voice comes back as ",(0,r.kt)("inlineCode",{parentName:"p"},"null"),"; avatar and behavior are required. Native code converts CAMP animation lists/tags into the controller's editable behavior format and downloads their OZZ clips through the shared asset cache."),(0,r.kt)("h3",{id:"avataranimationcontroller"},(0,r.kt)("inlineCode",{parentName:"h3"},"AvatarAnimationController")),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Group"),(0,r.kt)("th",{parentName:"tr",align:null},"APIs"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Lifecycle"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"update(dt)"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"syncPose()"),", ",(0,r.kt)("inlineCode",{parentName:"td"}
1,"dispose()"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"hasAnimation"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"isPaused"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"isDisposed"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"blinkEnabled"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Load clips"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"loadClip(source, version?)"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"loadClipFromAssetResolver(...)"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"loadClipFromBuffer(...)"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Playback"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"setIdle"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"playGesture"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"setTalking"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"setEmotion"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"playEmotionBody"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"playGestureTag"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"playEmotion"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"playGUID"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Time"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"getIdleTime"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"setIdleTime"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"getChannelInfo"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"getChannelCurrentTime"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"setChannelCurrentTime"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Weights"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"setIdleWeight"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"setTalkingWeight"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"setTalkingEnabled"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"setEmotionWeight"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"setBoredomWeight"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"setGestureWeight"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"setBreathWeight"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"setAutoBoredom"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Weight read-back"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"getChannelWeights"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"getTalkingWeight"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"getLookWeight"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"getGazeWeight"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Retargeting"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"setAllRetargetEnabled"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"getAllRetargetEnabled"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"setRetargetEnabled"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"getRetargetEnabled"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Look and gaze"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"setLookWeight"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"setGazeWeight"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"getHeadBone"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"setLookAtCamera"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"setAttentionTemplate"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Behavior"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"loadSmartAvatarBehavior"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"loadSmartAvatarBehaviorFromConfig"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"getBehaviorConfig"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"setBehaviorConfig"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"getAvailableAnimTags"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Graph tooling"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"serializeGraph"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"applyGraphParams"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Current state"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"getCurrentBoredGUID"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"getCurrentSecondaryGUID"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"getCurrentGestureGUID"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"getCurrentEmotion"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Voice"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"setVoiceAnimation"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"getVoiceAnimationTime"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"setVoiceAnimationTime"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"getTalkingActive"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"stopVoiceAnimation"))))),(0,r.kt)("p",null,"Channel names are ",(0,r.kt)("inlineCode",{parentName:"p"},"idle"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"boredom"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"gesture"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"breath"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"baseEmotion"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"emote1")," through ",(0,r.kt)("inlineCode",{parentName:"p"},"emote4"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"talking"),", and ",(0,r.kt)("inlineCode",{parentName:"p"},"secondary"),". Use ",(0,r.kt)("inlineCode",{parentName:"p"},"getChannelCurrentTime()")," for low-allocation frame polling."),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Loading clips.")," ",(0,r.kt)("inlineCode",{parentName:"p"},"controller.loadClip(source, version?)")," accepts a local OZZ path, a legacy ",(0,r.kt)("inlineCode",{parentName:"p"},"AnimationLibrary/...")," ID, or a CAMP ",(0,r.kt)("inlineCode",{parentName:"p"},"bm_anim-asset_*")," ID, and returns an ",(0,r.kt)("inlineCode",{parentName:"p"},"AnimationClip"),". ",(0,r.kt)("inlineCode",{parentName:"p"},"loadAnimation(id, version?)")," accepts either resolver ID format and returns the raw bytes instead. The optional version applies only to legacy IDs. CAMP loading resolves ",(0,r.kt)("inlineCode",{parentName:"p"},"runtimeOzz")," internally \u2014 you don't need resolver documents or artifact URLs."),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Playing gestures.")," Use ",(0,r.kt)("inlineCode",{parentName:"p"},"playGesture(clip, options?)")," for a loaded clip. After behavior loading, ",(0,r.kt)("inlineCode",{parentName:"p"},"getAvailableAnimTags()")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"playGestureTag(tag, onComplete?, startTime?)")," work with both legacy and CAMP behavior sources (",(0,r.kt)("inlineCode",{parentName:"p"},"startTime")," is in seconds). Note that loading an individual clip does ",(0,r.kt)("em",{parentName:"p"},"not")," register behavior tags. The lower-level ",(0,r.kt)("inlineCode",{parentName:"p"},"loadSmartAvatarBehavior(slug, ...)")," remains the legacy slug loader \u2014 use ",(0,r.kt)("inlineCode",{parentName:"p"},"activateBehavior(controller, { behaviorId })")," for a CAMP behavior ID."),(0,r.kt)("admonition",{title:"Clip cleanup",type:"note"},(0,r.kt)("p",{parentName:"admonition"},"There is no public per-clip removal API. Controller disposal releases its clip handles, while shared native clip data may remain cached for reuse. An avatar's ",(0,r.kt)("inlineCode",{parentName:"p"},"unload()")," disposes its controller automatically.")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"}
1,"Retargeting")," can be enabled globally or per body channel: ",(0,r.kt)("inlineCode",{parentName:"p"},"idle"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"boredom"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"secondary"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"gesture"),", and ",(0,r.kt)("inlineCode",{parentName:"p"},"breath"),". Source height, coordinate space, and motion descriptors are baked clip metadata and remain read-only."),(0,r.kt)("h3",{id:"dynamics-ik-and-body-motion"},"Dynamics, IK, and body motion"),(0,r.kt)("p",null,"Dynamics is physics-based secondary motion \u2014 hair, cloth, and accessories that sway and settle as the avatar moves. Its configuration ships with the asset in the ",(0,r.kt)("inlineCode",{parentName:"p"},"GENIES_dynamics")," extension."),(0,r.kt)("p",null,"A ",(0,r.kt)("strong",{parentName:"p"},"rig recipe")," is the companion setup for the avatar's skeleton: it declares how the rig is assembled and corrected \u2014 which joints drive which, how IK is wired, and which twist corrections to apply. It ships with the asset in the ",(0,r.kt)("inlineCode",{parentName:"p"},"GENIES_rig_recipe")," extension."),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Body motion")," is procedural idle movement \u2014 the small, continuous adjustments that keep a standing avatar from looking frozen. It is driven by four sub-configs: ",(0,r.kt)("inlineCode",{parentName:"p"},"balance")," (shifting weight between the feet over time), ",(0,r.kt)("inlineCode",{parentName:"p"},"posture")," (spine bend and how open the clavicles, elbows, knees, and legs sit), ",(0,r.kt)("inlineCode",{parentName:"p"},"micro")," (small fidgets), and ",(0,r.kt)("inlineCode",{parentName:"p"},"gaze")," (looking around, including how much the torso follows). It runs together with full-body IK (FBIK), so ",(0,r.kt)("inlineCode",{parentName:"p"},"setFBIKEnabled(false)")," turns procedural body motion off as well."),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Dynamics and rig recipes are applied automatically by the high-level avatar flow")," \u2014 no consumer call is required. The direct controller APIs below exist for runtime tools:"),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Area"),(0,r.kt)("th",{parentName:"tr",align:null},"APIs"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Dynamics"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"appendDynamicsGroup"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"clearDynamics"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"resetSimulation"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"setDynamicsEnabled"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"setDynamicsWeight"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"getDynamicsWeight"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"getLastDynamicsGroupError"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Rig recipe"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"setRigRecipeConfig"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"getRigRecipeConfig"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"getLastRigRecipeConfigError"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"IK"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"setFBIKEnabled"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"getFBIKEnabled"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Body motion config"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"setBodyMotionConfig"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"getBodyMotionConfig"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"getLastBodyMotionConfigError"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"getBodyMotionDiagnostics"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Body motion commands"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"playBodyMotionGesture"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"setBodyMotionBalanceLibrary"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"forceBodyMotionSide"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"forceBodyMotionStance"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"forceBodyMotionFidget"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"getLastBodyMotionCommandError"))))),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"BodyMotionConfig")," is a ",(0,r.kt)("strong",{parentName:"p"},"partial merge")," \u2014 it merges into the active configuration rather than replacing it. A balance library, by contrast, is replaced as one coherent graph. Check the diagnostics and last-error APIs after runtime edits."),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"DynamicsConfigLoader")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"RigRecipeConfigLoader")," can fetch or apply external JSON directly, for when automatic extension resolution isn't what you want."),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Skeleton fixups.")," Rig recipes also accept ",(0,r.kt)("inlineCode",{parentName:"p"},"skeletonFixups"),": an array of ",(0,r.kt)("inlineCode",{parentName:"p"}
1,"{ helper, target, weight, kind: 'twistY' }")," bindings. Each entry overrides one of the built-in default corrections, matched by its helper joint. (Those defaults are named for the standard Genies rig generation, Gen14 \u2014 most integrators never need to reference them directly.) Helper and target names you supply are validated against the avatar's actual skeleton, and any default joint the skeleton doesn't have is skipped. Inside the native animation graph, secondary dynamics runs ",(0,r.kt)("em",{parentName:"p"},"before")," these twist corrections, and emotion mouth closing runs ",(0,r.kt)("em",{parentName:"p"},"after")," voice animation."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"await avatar.setDynamicsOverride({ config: editedDynamics });\navatar.controller.setRigRecipeConfig(editedRecipe);\navatar.controller.setFBIKEnabled(true);\n")),(0,r.kt)("hr",null),(0,r.kt)("h2",{id:"managed-rendering"},"Managed rendering"),(0,r.kt)("p",null,"By default the SDK owns rendering for you: native code publishes render models, pose frames, scene state, visibility, and render-pass plans, and the Web frontend translates the approved work into Three.js/WebGL and presents it. Most apps never need to touch this \u2014 configure the scene through the APIs below, or opt out entirely with ",(0,r.kt)("inlineCode",{parentName:"p"},"managedRenderFrontend: false")," plus ",(0,r.kt)("inlineCode",{parentName:"p"},"advanced.rendering"),"."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"API"),(0,r.kt)("th",{parentName:"tr",align:null},"Purpose"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"configureRenderer(config, options?)")),(0,r.kt)("td",{parentName:"tr",align:null},"Apply a partial scene configuration and return status, diagnostics, and effective state.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"getRendererCapabilities()")),(0,r.kt)("td",{parentName:"tr",align:null},"Return backend features, limits, and sample counts.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"getRendererConfiguration()")),(0,r.kt)("td",{parentName:"tr",align:null},"Return the effective scene state and revision.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"setRendererTexture(slot, texture)")),(0,r.kt)("td",{parentName:"tr",align:null},"Bind or clear a Three.js scene texture. Returns ",(0,r.kt)("inlineCode",{parentName:"td"},"true"),"; invalid input or backend rejection throws.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"getRendererMetrics()")," / ",(0,r.kt)("inlineCode",{parentName:"td"},"resetRendererMetrics()")),(0,r.kt)("td",{parentName:"tr",align:null},"Read or reset native render publication and logical-memory metrics.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"RendererFallbackPolicy")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"STRICT")," or ",(0,r.kt)("inlineCode",{parentName:"td"},"DISABLE_UNSUPPORTED"),".")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"RendererTextureSlot")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"BACKGROUND"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"ENVIRONMENT"),", or ",(0,r.kt)("inlineCode",{parentName:"td"},"COLOR_GRADING_LUT"),".")))),(0,r.kt)("p",null,"Configuration sections are ",(0,r.kt)("inlineCode",{parentName:"p"},"camera"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"directionalLights"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"environment"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"shadows"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"outline"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"silhouette"),", and ",(0,r.kt)("inlineCode",{parentName:"p"},"postProcess"),". Omitted sections retain their current state. In ",(0,r.kt)("strong",{parentName:"p"},"strict")," mode unsupported requests are rejected; in ",(0,r.kt)("strong",{parentName:"p"},"disable-unsupported")," mode the supported subset is applied and the changes are reported."),(0,r.kt)("admonition",{title:"Reading the metrics correctly",type:"note"},(0,r.kt)("p",{parentName:"admonition"},(0,r.kt)("inlineCode",{parentName:"p"},"getRendererMetrics().currentLogicalModelBytes")," measures logical render-model buffers \u2014 not total WASM heap, refitting working memory, or GPU allocation bytes.")),(0,r.kt)("hr",null),(0,r.kt)("h2",{id:"materials-and-shaders"},"Materials and shaders"),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"getShaderManager()")," returns the SDK singleton. Avatar loading, LOD changes, rebuilds, and unloads automatically attach, refresh, and detach shader state."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"API"),(0,r.kt)("th",{parentName:"tr",align:null},"Purpose"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"getShaderManager()")),(0,r.kt)("td",{parentName:"tr",align:null},"Access the active avatar's toon, outline, preset, and material controls.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"mergeMegaStylizerPresets(layers)")),(0,r.kt)("td",{parentName:"tr",align:null},"Merge ordered preset layers without applying them.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"manager.applyShaderPreset(preset)")),(0,r.kt)("td",{parentName:"tr",align:null},"Replace the active avatar's effective preset.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"manager.applyShaderPresetLayers(layers)")),(0,r.kt)("td",{parentName:"tr",align:null},"Merge layers and apply the result once.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"manager.setActiveAvatar(id)")),(0,r.kt)("td",{parentName:"tr",align:null},"Select the avatar affected by subsequent controls.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"manager.setActiveMesh(name, materialIndex?)")),(0,r.kt)("td",{parentName:"tr",align:null},"Scope controls to one mesh or material; pass ",(0,r.kt)("inlineCode",{parentName:"td"},"null")," to clear.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"manager.getMeshNames()")," / ",(0,r.kt)("inlineCode",{parentName:"td"},"getMeshMaterials()")),(0,r.kt)("td",{parentName:"tr",align:null},"Inspect available scopes; material entries include ",(0,r.kt)("inlineCode",{parentName:"td"},"sourceMeshIds")," and ",(0,r.kt)("inlineCode",{parentName:"td"},"sourceAssetIds"),".")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"manager.setRgbaMaskColors(params)")),(0,r.kt)("td",{parentName:"tr",align:null},"Update RGBA/RGBK mask colors for the active scope (see ",(0,r.kt)("a",{parentName:"td",href:"#rgbk-colors"},"RGBK colors"),").")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"manager.toon")," / ",(0,r.kt)("inlineCode",{parentName:"td"},"manager.outline")),(0,r.kt)("td",{parentName:"tr",align:null},"Typed effect-specific controls.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"manager.dispose()")),(0,r.kt)("td",{parentName:"tr",align:null},"Dispose all managed effect state.")))),(0,r.kt)("h3",{id:"built-in-effects"},"Built-in effects"),(0,r.kt)("p",null,"Two effects are built in and controlled through the manager: ",(0,r.kt)("strong",{parentName:"p"},"Toon")," (cel / stylized shading) and ",(0,r.kt)("strong",{parentName:"p"},"Outline")," (a drawn outline around the avatar). You can adjust either live with individual setter calls, or describe a whole look at once with a JSON preset."),(0,r.kt)("p",null,"Together these make up the ",(0,r.kt)("strong",{parentName:"p"},"Mega Stylizer")," \u2014 the SDK's stylized shading system. A ",(0,r.kt)("em",{parentName:"p"},"Mega Stylizer preset")," is a JSON document describing an avatar's complete authored look: toon shading values, outline settings, and surface state such as transparency."),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Toon")," (",(0,r.kt)("inlineCode",{parentName:"p"},"manager.toon"),") \u2014 stylized cel shading. Supports typed ",(0,r.kt)("inlineCode",{parentName:"p"},"setParam")," / ",(0,r.kt)("inlineCode",{parentName:"p"},"getParam"),", preset, material-model, and scoped read-back APIs. A few parameters you'll reach for most:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"strong"},"cartoonMix"))," blends between realistic and toon shading: ",(0,r.kt)("inlineCode",{parentName:"li"}
1,"0")," is fully lit (realistic), ",(0,r.kt)("inlineCode",{parentName:"li"},"1")," is fully toon, and values in between are a hybrid."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"strong"},"aoAlbedoDarken"))," darkens the base color in ambient-occlusion areas \u2014 crevices and contact shadows \u2014 for a more hand-painted look. ",(0,r.kt)("inlineCode",{parentName:"li"},"0")," leaves the color untouched; higher values deepen it."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"strong"},"useOrmAlpha"))," (",(0,r.kt)("inlineCode",{parentName:"li"},"0"),"\u2013",(0,r.kt)("inlineCode",{parentName:"li"},"1"),") applies to glTF materials only; it's ignored (forced to ",(0,r.kt)("inlineCode",{parentName:"li"},"0"),") on legacy Unity-URP materials.")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Outline")," (",(0,r.kt)("inlineCode",{parentName:"p"},"manager.outline"),") \u2014 draws an outline around the avatar (an inverted-hull outline). Its controls fall into three groups:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"Appearance:")," enable, thickness, color, alpha, width, depth bias, and resolution."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"Silhouette gating:")," ",(0,r.kt)("inlineCode",{parentName:"li"},"setSilhouetteGate(v)"),", ",(0,r.kt)("inlineCode",{parentName:"li"},"setGateGeomMix(v)"),", ",(0,r.kt)("inlineCode",{parentName:"li"},"setGateStrictness(v)"),"."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"Scope + read-back:")," ",(0,r.kt)("inlineCode",{parentName:"li"},"setActiveMesh(name)"),", ",(0,r.kt)("inlineCode",{parentName:"li"},"getMeshNames()"),", ",(0,r.kt)("inlineCode",{parentName:"li"},"getMeshParams(name?)"),".")),(0,r.kt)("p",null,(0,r.kt)("em",{parentName:"p"},"Silhouette gating")," restricts the outline to the model's silhouette \u2014 its contour (rim) edges \u2014 instead of drawing it across flat, front-facing surfaces. ",(0,r.kt)("inlineCode",{parentName:"p"},"setSilhouetteGate(0)")," disables gating so the outline is drawn everywhere; any value above ",(0,r.kt)("inlineCode",{parentName:"p"},"0")," turns it on and trims the non-silhouette parts. In a preset, the matching fields are ",(0,r.kt)("inlineCode",{parentName:"p"},"outlineSilhouetteGate"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"outlineGateGeomMix"),", and ",(0,r.kt)("inlineCode",{parentName:"p"},"outlineGateStrictness"),"."),(0,r.kt)("admonition",{title:"Full parameter set",type:"info"},(0,r.kt)("p",{parentName:"admonition"},"Refer to ",(0,r.kt)("inlineCode",{parentName:"p"},"MegaStylizerParameters"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"MegaStylizerPreset"),", and ",(0,r.kt)("inlineCode",{parentName:"p"},"ShaderManager")," in the type declarations for every available parameter.")),(0,r.kt)("h3",{id:"presets-are-json"},"Presets are JSON"),(0,r.kt)("p",null,"A preset is a plain JSON object describing the look you want, which you hand to ",(0,r.kt)("inlineCode",{parentName:"p"},"applyShaderPreset()"),". Presets support global properties plus three scoping maps:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"strong"},"multiMesh"))," \u2014 keyed by mesh target."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"strong"},"multiMaterial"))," \u2014 keyed by material name."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"strong"},"multiAsset"))," \u2014 keyed by stable public asset ID. Each entry holds a ",(0,r.kt)("em",{parentName:"li"},"complete")," preset, including its own mesh and material overrides, and affects only materials belonging to that asset \u2014 not the whole avatar.")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Surface state \u2014 transparency and culling.")," These optional fields control how a material draws:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"alphaMode")," \u2014 ",(0,r.kt)("inlineCode",{parentName:"li"},"OPAQUE"),", ",(0,r.kt)("inlineCode",{parentName:"li"},"MASK")," (a hard cutout using ",(0,r.kt)("inlineCode",{parentName:"li"},"alphaCutoff"),"), or ",(0,r.kt)("inlineCode",{parentName:"li"},"BLEND")," (soft transparency)."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"alphaCutoff")," \u2014 the threshold used by ",(0,r.kt)("inlineCode",{parentName:"li"},"MASK"),"."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"opacity")," \u2014 overall opacity. Setting ",(0,r.kt)("inlineCode",{parentName:"li"},"opacity")," on its own does ",(0,r.kt)("strong",{parentName:"li"},"not")," turn on transparency; use ",(0,r.kt)("inlineCode",{parentName:"li"},'alphaMode: "BLEND"')," for that."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"doubleSided")," \u2014 render both faces of a surface instead of culling the back."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"depthWrite")," \u2014 whether the material writes to the depth buffer. ",(0,r.kt)("inlineCode",{parentName:"li"},"BLEND")," defaults this to ",(0,r.kt)("inlineCode",{parentName:"li"},"false"),".")),(0,r.kt)("p",null,"For example \u2014 make everything a hard cutout, but let the hair blend softly:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json"},'{\n "alphaMode": "MASK",\n "alphaCutoff": 0.5,\n "doubleSided": true,\n "opacity": 1,\n "depthWrite": true,\n "useOrmAlpha": 0,\n "multiMaterial": {\n "HairMaterial": {\n "alphaMode": "BLEND",\n "opacity": 0.8,\n "depthWrite": false,\n "useOrmAlpha": 1\n }\n }\n}\n')),(0,r.kt)("p",null,"For convenience \u2014 and to keep older presets working \u2014 a few fields accept alternate names that map onto the canonical field:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"alphaOpacity")," \u2192 ",(0,r.kt)("inlineCode",{parentName:"li"},"opacity")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"twoSided")," \u2192 ",(0,r.kt)("inlineCode",{parentName:"li"},"doubleSided")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"alphaEnabled")," \u2192 ",(0,r.kt)("inlineCode",{parentName:"li"},"alphaMode"),": ",(0,r.kt)("inlineCode",{parentName:"li"},"false")," becomes ",(0,r.kt)("inlineCode",{parentName:"li"},"OPAQUE"),"; ",(0,r.kt)("inlineCode",{parentName:"li"},"true")," becomes ",(0,r.kt)("inlineCode",{parentName:"li"},"MASK")," when a positive ",(0,r.kt)("inlineCode",{parentName:"li"},"alphaCutoff")," is set, otherwise ",(0,r.kt)("inlineCode",{parentName:"li"},"BLEND"),".")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Using presets with TypeScript.")," The SDK ships types so your editor can autocomplete preset fields and catch typos before you run. Import ",(0,r.kt)("inlineCode",{parentName:"p"},"MegaStylizerPreset")," for the JSON shape accepted by ",(0,r.kt)("inlineCode",{parentName:"p"},"applyShaderPreset()"),", or ",(0,r.kt)("inlineCode",{parentName:"p"},"MegaStylizerParameters")," for the canonical ",(0,r.kt)("inlineCode",{parentName:"p"},"toon.setParam()")," values. Applying ",(0,r.kt)("inlineCode",{parentName:"p"},"satisfies MegaStylizerPreset")," gives you full IntelliSense and rejects unknown fields:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-ts"},"import { getShaderManager, type MegaStylizerPreset } from '@geniesinc/genies-naf-webgl';\n\nconst preset = {\n cartoonMix: 0.8,\n albedoSaturation: 1.1,\n alphaMode: 'MASK',\n alphaCutoff: 0.5,\n outlineEnabled: true,\n outlineSilhouetteGate: 0.2,\n multiMaterial: {\n HairMaterial: { alph
1aMode: 'BLEND', opacity: 0.8, depthWrite: false }\n }\n} satisfies MegaStylizerPreset;\n\ngetShaderManager().applyShaderPreset(preset);\n")),(0,r.kt)("h3",{id:"preset-layers-and-asset-scopes"},"Preset layers and asset scopes"),(0,r.kt)("p",null,"Layers let you stack presets in order \u2014 for example, keep an avatar's authored look as the base and apply a wearable's overrides on top. Merge rules for ",(0,r.kt)("inlineCode",{parentName:"p"},"mergeMegaStylizerPresets()")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"applyShaderPresetLayers()"),":"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},"Layers are applied from lowest to highest priority."),(0,r.kt)("li",{parentName:"ol"},"Later values replace earlier values, including arrays and non-scoped objects."),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"multiMesh"),", ",(0,r.kt)("inlineCode",{parentName:"li"},"multiMaterial"),", and ",(0,r.kt)("inlineCode",{parentName:"li"},"multiAsset")," merge recursively by target/property."),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"null")," removes an inherited property, target, or map; ",(0,r.kt)("inlineCode",{parentName:"li"},"undefined")," is ignored."),(0,r.kt)("li",{parentName:"ol"},"Inputs are never mutated; results are independent copies.")),(0,r.kt)("p",null,"For a matching material, runtime precedence from lowest to highest is: avatar-global, avatar ",(0,r.kt)("inlineCode",{parentName:"p"},"multiMesh"),", asset-global, asset ",(0,r.kt)("inlineCode",{parentName:"p"},"multiMesh"),", avatar ",(0,r.kt)("inlineCode",{parentName:"p"},"multiMaterial"),", then asset ",(0,r.kt)("inlineCode",{parentName:"p"},"multiMaterial"),"."),(0,r.kt)("p",null,"The SDK normalizes source ",(0,r.kt)("inlineCode",{parentName:"p"},"shaderPresets.megaStylizer"),", preferring it over the legacy ",(0,r.kt)("inlineCode",{parentName:"p"},"shaderPresets.toonParams")," alias. Loading applies the source preset; successful equip, unequip, and replacement update the asset scopes automatically, and failed rebuilds roll preset changes back. Asset and mesh identity is retained through mesh combination, rebuilds, and dynamic LOD updates."),(0,r.kt)("p",null,"Use ",(0,r.kt)("inlineCode",{parentName:"p"},"handle.getSourceShaderPreset()")," as the first layer when your overrides must preserve the source-authored preset. Keep wearable overrides under their asset ID rather than adding a wearable's global preset as an avatar-wide layer:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"const shaders = getShaderManager();\nshaders.setActiveAvatar(avatar.avatarId);\nshaders.applyShaderPresetLayers([\n avatar.getSourceShaderPreset(),\n { multiAsset: { [wearableId]: wearablePreset } },\n].filter(Boolean));\n")),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"material.userData.sourceAssetIds")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"sourceMeshIds")," expose source identity for inspection. Asset matching does not depend on display names or unique material names, and authored mesh targets inside an asset scope are normalized internally \u2014 so you don't need combined-mesh naming conventions."),(0,r.kt)("p",null,"Extra native textures are exposed as ",(0,r.kt)("inlineCode",{parentName:"p"},"material.nafTextures"),"; binding metadata is available under ",(0,r.kt)("inlineCode",{parentName:"p"},"material.userData.nafTextureSlots"),"."),(0,r.kt)("h3",{id:"rgbk-colors"},"RGBK colors"),(0,r.kt)("p",null,"An ",(0,r.kt)("strong",{parentName:"p"},"RGBK mask")," is a texture that divides a material into up to four independently recolorable zones \u2014 one per channel: ",(0,r.kt)("strong",{parentName:"p"},"R"),"ed, ",(0,r.kt)("strong",{parentName:"p"},"G"),"reen, ",(0,r.kt)("strong",{parentName:"p"},"B"),"lue, and ",(0,r.kt)("strong",{parentName:"p"},"K")," (the fourth/key channel). The mask doesn't hold the colors itself; it marks which pixels belong to which zone, so assigning a color to a channel recolors just that region. A single jacket texture can, for example, keep the body, trim, lining, and buttons on separate channels so each can be tinted independently without new textures."),(0,r.kt)("p",null,"Each zone maps to a color attribute ID \u2014 ",(0,r.kt)("inlineCode",{parentName:"p"},"rgbk-r"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"rgbk-g"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"rgbk-b"),", and ",(0,r.kt)("inlineCode",{parentName:"p"},"rgbk-k"),"."),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"loadAvatar()")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"loadAvatarProgressive()")," apply valid source-authored RGBK swatches from wearables already included in a CAMP avatar, and equipping or replacing a CAMP wearable applies its swatches too. Colors use native attributes scoped to that asset; missing or invalid swatches leave existing values unchanged."),(0,r.kt)("p",null,"Use ",(0,r.kt)("inlineCode",{parentName:"p"},"getColorAttributes()")," to discover which IDs an avatar actually exposes, then ",(0,r.kt)("inlineCode",{parentName:"p"},"setColor(colorId, color, { assetId })")," / ",(0,r.kt)("inlineCode",{parentName:"p"},"unsetColor(colorId, { assetId })")," for runtime edits."),(0,r.kt)("admonition",{type:"note"},(0,r.kt)("p",{parentName:"admonition"},"Procedural texture baking must be enabled for these native color edits to affect baked output textures. RGBK colors are separate from Mega Stylizer presets and the shader manager's mask-color controls \u2014 ",(0,r.kt)("inlineCode",{parentName:"p"},"getSourceShaderPreset()")," does not return RGBK color overrides.")),(0,r.kt)("hr",null),(0,r.kt)("h2",{id:"assets-and-cache"},"Assets and cache"),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"API"),(0,r.kt)("th",{parentName:"tr",align:null},"Purpose"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"preloadAssets(source, lods?)")),(0,r.kt)("td",{parentName:"tr",align:null},"Resolve and cache all assets for an avatar source.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"prefetchAsset(id, { version?, lod? })")),(0,r.kt)("td",{parentName:"tr",align:null},"Cache one supported asset without decoding it.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"prefetchAssets(requests)")),(0,r.kt)("td",{parentName:"tr",align:null},"Fail-soft batch prefetch with per-item results and one trailing filesystem sync.")))),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"prefetchAssets()")," returns ",(0,r.kt)("inlineCode",{parentName:"p"},"{ results, succeeded, failed, synced }"),". Each result contains ",(0,r.kt)("inlineCode",{parentName:"p"},"{ key, id, version, lod, ok, error? }"),"."),(0,r.kt)("hr",null),(0,r.kt)("h2",{id:"voice-helpers"},"Voice helpers"),(0,r.kt)("p",null,"Audio playback remains consumer-owned. The SDK parses response payloads and installs blendsh
1ape frames on an animation controller."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"API"),(0,r.kt)("th",{parentName:"tr",align:null},"Purpose"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"configureVoice(config)")," / ",(0,r.kt)("inlineCode",{parentName:"td"},"getVoiceConfiguration()")),(0,r.kt)("td",{parentName:"tr",align:null},"Set or read response fields, frame width, frame rate, and default gain.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"parseVoiceBlendshapes(response)")),(0,r.kt)("td",{parentName:"tr",align:null},"Parse flat, nested, or indexed blendshape frames.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"parseVoiceTags(response)")),(0,r.kt)("td",{parentName:"tr",align:null},"Parse sorted gesture and emotion tags.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"extractVoiceAudio(response)")),(0,r.kt)("td",{parentName:"tr",align:null},"Return the configured base64 audio field.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"loadVoiceAnimation(controller, frames, gain?)")),(0,r.kt)("td",{parentName:"tr",align:null},"Install parsed frames on a controller.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"loadVoiceConfig(path)")),(0,r.kt)("td",{parentName:"tr",align:null},"Fetch and apply voice configuration JSON.")))),(0,r.kt)("hr",null),(0,r.kt)("h2",{id:"events"},"Events"),(0,r.kt)("p",null,"Use ",(0,r.kt)("inlineCode",{parentName:"p"},"on"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"once"),", and ",(0,r.kt)("inlineCode",{parentName:"p"},"off"),". Both ",(0,r.kt)("inlineCode",{parentName:"p"},"on()")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"once()")," return an unsubscribe function. Event emission is SDK-owned."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"const unsubscribe = naf.on('avatar:ready', ({ avatarId, initialLod }) => {\n console.log(avatarId, initialLod);\n});\n")),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Event"),(0,r.kt)("th",{parentName:"tr",align:null},"Key payload fields"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"initialized")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"instance"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"native-error")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"caller"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"message"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"avatar:silhouette")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"mesh"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"controller?"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"avatar:ready")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"avatarId"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"mesh"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"controller"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"previousMesh"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"initialLod"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"avatar:loaded")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"avatarId"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"handle"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"avatar:lod-upgrade")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"avatarId"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"targetLod"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"assetId?"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"avatar:textures-updated")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"avatarId"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"skinnedMesh"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"avatar:rebuild-start")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"avatarId"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"mesh"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"avatar:rebuilt")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"avatarId"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"mesh"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"controller"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"avatar:unloaded")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"avatarId"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"avatar:behavior-loaded")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"avatarId"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"controller"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"avatar:dynamics-changed")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"avatarId?"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"controller"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"source"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"active"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"error"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"overrideError"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"avatar:channel-start")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"avatarId"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"channel"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"guid"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"duration"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"isLooping"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"avatar:channel-end")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"avatarId"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"channel"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"guid"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"completed"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"avatar:error")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"avatarId?"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"error"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"phase"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"textures-ready")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"avatars"))))),(0,r.kt)("h3",{id:"event-error-phases"},"Event error phases"),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"phase")," field on ",(0,r.kt)("inlineCode",{parentName:"p"},"avatar:error")," identifies where in the pipeline the error occurred:"),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Phase"),(0,r.kt)("th",{parentName:"tr",align:null},"Fatal?"),(0,r.kt)("th",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"th"},"avatarId")," present?"),(0,r.kt)("th",{parentName:"tr",align:null},"Description"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"avatar-resolve")),(0,r.kt)("td",{parentName:"tr",align:null},"\u2014"),(0,r.kt)("td",{parentName:"tr",align:null},"\u2014"),(0,r.kt)("td",{parentName:"tr",align:null},"Resolving an avatar source (such as a CAMP ID) failed.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"avatar-load")),(0,r.kt)("td",{parentName:"tr",align:null},"Yes"),(0,r.kt)("td",{parentName:"tr",align:null},"No (",(0,r.kt)("inlineCode",{parentName:"td"},"avatarDefinition")," included instead)"),(0,r.kt)("td",{parentName:"tr",align:null},"Avatar load failed \u2014 all asset resolver fallbacks exhausted. The promise rejects.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"native")),(0,r.kt)("td",{parentName:"tr",align:null},"No"),(0,r.kt)("td",{parentName:"tr",align:null},"No"),(0,r.kt)("td",{parentName:"tr",align:null},"Native-side error forwarded during load (e.g. a single resolver endpoint failing before fallback). Informational only.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"silhouette")),(0,r.kt)("td",{parentName:"tr",align:null},"No"),(0,r.kt)("td",{parentName:"tr",align:null},"No"),(0,r.kt)("td",{parentName:"tr",align:null},"Silhouette mesh construction failed. Avatar load continues.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"silhouette-animation")),(0,r.kt)("td",{parentName:"tr",align:null},"No"),(0,r.kt)("td",{parentName:"tr",align:null},"No"),(0,r.kt)("td",{parentName:"tr",align:null},"Failed to animate the silhouette. Avatar load continues.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"animation")),(0,r.kt)("td",{parentName:"tr",align:null},"No"),(0,r.kt)("td",{parentName:"tr",align:null},"Yes"),(0,r.kt)("td",{parentName:"tr",align:null},"Animation controller or idle clip setup failed after avatar loaded.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"behavior")),(0,r.kt)("td",{parentName:"tr",align:null},"No"),(0,r.kt)("td",{parentName:"tr",align:null},"Yes"),(0,r.kt)("td",{parentName:"tr",align:null},"Smart avatar behavior activation failed.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"lod-upgrade")),(0,r.kt)("td",{parentName:"tr",align:null},"No"),(0,r.kt)("td",{parentName:"tr",align:null},"Yes"),(0,r.kt)("td",{parentName:"tr",align:null},"A background LOD texture upgrade failed. Avatar remains at previous LOD.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"rebuild")),(0,r.kt)("td",{parentName:"tr",align:null},"Yes"),(0,r.kt)("td",{parentName:"tr",align:null},"Yes"),(0,r.kt)("td",{parentName:"tr",align:null},"Full rebuild (",(0,r.kt)("inlineCode",{parentName:"td"},"equipAsset"),"/",(0,r.kt)("inlineCode",{parentName:"td"},"unequipAsset"),") failed. The promise rejects and the definition is rolled back.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"rebuild-animation")),(0,r.kt)("td",{parentName:"tr",align:null},"No"),(0,r.kt)("td",{parentName:"tr",align:null},"Yes"),(0,r.kt)("td",{parentName:"tr",align:null},"Animation controller failed during rebuild staging. Rebuild continues without animation.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"rebuild-behavior")),(0,r.kt)("td",{parentName:"tr",align:null},"No"),(0,r.kt)("td",{parentName:"tr",align:null},"Yes"),(0,r.kt)("td",{parentName:"tr",align:null}
1,"Behavior re-activation failed after rebuild.")))),(0,r.kt)("admonition",{type:"note"},(0,r.kt)("p",{parentName:"admonition"},(0,r.kt)("strong",{parentName:"p"},"Fatal")," means the calling promise rejects. Non-fatal errors are emitted for observability but the pipeline continues. The operation's returned promise remains the flow-control contract \u2014 events are for observation.")),(0,r.kt)("hr",null),(0,r.kt)("h2",{id:"logging-and-diagnostics"},"Logging and diagnostics"),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"API"),(0,r.kt)("th",{parentName:"tr",align:null},"Purpose"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"createLogger(tag)")),(0,r.kt)("td",{parentName:"tr",align:null},"Return a tagged logger with ",(0,r.kt)("inlineCode",{parentName:"td"},"debug"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"info"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"warn"),", and ",(0,r.kt)("inlineCode",{parentName:"td"},"error"),".")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"setLogLevel(level)")," / ",(0,r.kt)("inlineCode",{parentName:"td"},"LogLevel")),(0,r.kt)("td",{parentName:"tr",align:null},"Set global verbosity: ",(0,r.kt)("inlineCode",{parentName:"td"},"DEBUG"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"INFO"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"WARN"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"ERROR"),", or ",(0,r.kt)("inlineCode",{parentName:"td"},"NONE"),".")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"setLogMemoryBufferSize(n)")),(0,r.kt)("td",{parentName:"tr",align:null},"Set capacity; ",(0,r.kt)("inlineCode",{parentName:"td"},"0")," clears and disables capture.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"setLogMemoryBufferEnabled(enabled)")),(0,r.kt)("td",{parentName:"tr",align:null},"Pause or resume capture.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"isLogMemoryBufferEnabled()")),(0,r.kt)("td",{parentName:"tr",align:null},"Return capture state.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"getLogMemoryBuffer()")," / ",(0,r.kt)("inlineCode",{parentName:"td"},"getLogMemoryBufferSize()")),(0,r.kt)("td",{parentName:"tr",align:null},"Return a snapshot or entry count.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"clearLogMemoryBuffer()")),(0,r.kt)("td",{parentName:"tr",align:null},"Empty the buffer.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"dumpLogMemoryBuffer()")),(0,r.kt)("td",{parentName:"tr",align:null},"Print and return the current snapshot.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"setLogBufferFullCallback(callback)")),(0,r.kt)("td",{parentName:"tr",align:null},"Receive the snapshot before the oldest entry is dropped; pass ",(0,r.kt)("inlineCode",{parentName:"td"},"null")," to clear.")))),(0,r.kt)("p",null,"Entries have ",(0,r.kt)("inlineCode",{parentName:"p"},"{ timestamp, level, caller, message }"),"."),(0,r.kt)("hr",null),(0,r.kt)("h2",{id:"advanced-integrations"},"Advanced integrations"),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"advanced")," is a deliberate boundary for wrappers, tooling, and custom renderers. The high-level SDK flows already own these operations."),(0,r.kt)("admonition",{type:"caution"},(0,r.kt)("p",{parentName:"admonition"},"Do not mix ",(0,r.kt)("inlineCode",{parentName:"p"},"advanced")," APIs into a managed lifecycle without an explicit ownership design.")),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Namespace"),(0,r.kt)("th",{parentName:"tr",align:null},"APIs"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"advanced.runtime")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"ensureInitialized()"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"reset()"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"advanced.rendering")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"createMultiMeshAvatar"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"updateMaterialTextures"),", ",(0,r.kt)("inlineCode",{parentName:"td"}
1,"MegaShaderMaterial"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"OutlineMaterial"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"applyMegaShaderToMesh"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"advanced.animation")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"PoseSynchronizer"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"advanced.materialCompatibility")),(0,r.kt)("td",{parentName:"tr",align:null},"Unity metallic-smoothness conversion and roughness/smoothness controls")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"advanced.debug")),(0,r.kt)("td",{parentName:"tr",align:null},"Log window, animation overlays, and material overlays")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"advanced.filesystem")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"sync"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"writeFile"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"readFile"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"listFiles"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"advanced.lod")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"registerCallbacks"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"unregisterCallbacks"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"advanced.configuration")),(0,r.kt)("td",{parentName:"tr",align:null},"Resolver, pipeline, texture, coordinate-space, culling-UV guard, and material compatibility configuration")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"advanced.defaults")),(0,r.kt)("td",{parentName:"tr",align:null},"Read-only mesh, rotation, conversion, skeleton, and blendshape defaults")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"advanced.diagnostics")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"Profiler"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"onNativeError"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"advanced.ikRecipes")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"getSources(avatarId)"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"getMerged(avatarId)"))))),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"advanced.ikRecipes.getMerged()")," returns immutable builder composition output, while ",(0,r.kt)("inlineCode",{parentName:"p"},"controller.getRigRecipeConfig()")," returns the controller's effective runtime recipe after local edits."),(0,r.kt)("hr",null),(0,r.kt)("h2",{id:"content-authoring-tools"},"Content authoring tools"),(0,r.kt)("p",null,"The APIs above are for ",(0,r.kt)("em",{parentName:"p"},"running")," avatars. Content Tools is a separate, optional toolset for ",(0,r.kt)("em",{parentName:"p"},"authoring")," them \u2014 inspecting, editing, decoding, and regenerating the NAF FlatBuffer assets themselves. Most apps never need it; reach for it when you're building content pipelines or editor tooling."),(0,r.kt)("p",null,"Authoring tools are separate package subpaths and are ",(0,r.kt)("strong",{parentName:"p"},"not")," included in the runtime bundle:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"@geniesinc/genies-naf-webgl/content-tools")," \u2014 browser-safe."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"@geniesinc/genies-naf-webgl/content-tools/node")," \u2014 host orchestration."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"@geniesinc/genies-naf-content-tools")," \u2014 an optional development dependency containing ",(0,r.kt)("inlineCode",{parentName:"li"},"flatc"),", ",(0,r.kt)("inlineCode",{parentName:"li"},"nafshc"),", and Content Schemas.")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"npm install --save-dev @geniesinc/genies-naf-content-tools\n")),(0,r.kt)("h3",{id:"browser-safe-tools"},"Browser-safe tools"),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Area"),(0,r.kt)("th",{parentName:"tr",align:null},"APIs"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Host transport"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"NafContentToolsClient"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Definitions and assets"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"inspectAvatarDefinition"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"inspectCombinableAsset"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"inspectMaterialTextures"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Shader data"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"upsertShaderProgram"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"upsertShaderFlavor"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"getEmbeddedShaderFlavorData"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"upsertShaderSourceFlavor"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"RGBK"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"upsertRgbkMask"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"getRgbkMask"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"configureRgbkMaterial"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"JSON extensions"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"inspectJsonExtension"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"getJsonExtension"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"upsertJsonExtension"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"removeExtension"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Typed extensions"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"getDynamicsConfig"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"upsertDynamicsConfig"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"getRigRecipeConfig"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"upsertRigRecipeConfig"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Revisions"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"retargetCombinableAssetRevision"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"createLocalFixtureManifest"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"createLocalAvatarDefinition"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Local fixtures"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"client.saveLocalFixtureAsset(...)")," persists one generated revision through the configured host.")))),(0,r.kt)("p",null,"Browsers cannot execute ",(0,r.kt)("inlineCode",{parentName:"p"},"flatc")," or ",(0,r.kt)("inlineCode",{parentName:"p"},"nafshc"),", so browser consumers must connect ",(0,r.kt)("inlineCode",{parentName:"p"},"NafContentToolsClient")," to a trusted Node host."),(0,r.kt)("h3",{id:"node-tools"}
1,"Node tools"),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"API"),(0,r.kt)("th",{parentName:"tr",align:null},"Purpose"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"NafContentToolsHost")),(0,r.kt)("td",{parentName:"tr",align:null},"Resolve and invoke native authoring tools.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"NafContentToolsBridge")),(0,r.kt)("td",{parentName:"tr",align:null},"Implement the browser bridge contract.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"createContentToolsBridgeHandler()")),(0,r.kt)("td",{parentName:"tr",align:null},"Create a framework-neutral async request handler.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"resolveContentToolsHost()")),(0,r.kt)("td",{parentName:"tr",align:null},"Inspect resolved executable and schema paths.")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Decode/encode helpers"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"decodeCombinableAsset"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"encodeCombinableAsset"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"decodeContentManifest"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"decodeEmbeddedCombinableAssetConfig"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"createCombinableAssetRevision"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"ShaderCompiler.compile(...)")," / ",(0,r.kt)("inlineCode",{parentName:"td"},"compileSource(...)")),(0,r.kt)("td",{parentName:"tr",align:null},"Produce ",(0,r.kt)("inlineCode",{parentName:"td"},"slang-ir"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"glsl-es"),", and reflection metadata through ",(0,r.kt)("inlineCode",{parentName:"td"},"nafshc"),".")))),(0,r.kt)("p",null,"Applications own bridge authentication, request limits, HTTP status mapping, and filesystem policy."))}k.isMDXComponent=!0}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.