/** * character-render-xr — native-WebGPU WebXR character rendering (headset path). * * Additive SIBLING of renderCharacter (which stays the untouched G.GOLD.006 headless floor). * Where renderCharacter draws once to an offscreen texture + reads back, this drives the SAME * skinned-character pipeline per-XRView into the headset swapchain via XRWebGPUBinding projection * layers — no readback, composited straight to the display. * * VERIFICATION BOUNDARY (honest scope — refuse the demote): * - Headless-verifiable (unit-tested here): `detectSupport()` feature-detect + graceful * fallback (G.GOLD.006), `composeEyeViewProj()` per-eye math, `packFrameUniform()` layout. * - ON-DEVICE-PENDING (cannot run in CI/Dawn — needs a real Quest + XRWebGPUBinding): * the requestSession → binding → projection-layer → getViewerPose → per-eye composite loop * in `XRCharacterRenderer`. It compiles + is typed (no `any`/@ts-ignore), but the in-headset * render is provable only by running on-device (emit a quest-proof receipt there). * - Today XRWebGPUBinding support is uneven on headsets; detectSupport falls back to the * existing WebGL three.js path when it is absent — that fallback is the expected outcome * until devices confirm the binding. * * @module character-render */ import type { CharacterHost } from './CharacterHost'; import { type Mat4 } from './skin-math'; export type XRRenderMode = 'xr-webgpu' | 'webgl-fallback' | 'flat'; export interface XRSupport { webgpu: boolean; immersiveVR: boolean; xrWebGPUBinding: boolean; mode: XRRenderMode; reason: string; } /** * Feature-detect the native-WebGPU XR path; NEVER throws (G.GOLD.006 graceful fallback). * Returns a discriminated result the caller routes on: xr-webgpu → this module; webgl-fallback * → the existing three.js ImmersiveViewer; flat → offscreen renderCharacter preview. */ export declare function detectSupport(): Promise; /** Per-eye view·projection from an XRView: projectionMatrix · inverse(view transform). Column-major. */ export declare function composeEyeViewProj(projectionMatrix: Float32Array, viewInverseMatrix: Float32Array): Mat4; /** Pack the 40-float Frame uniform (mvp16 + model16 + cameraPos4 + lightDir4) — matches skin-skinning.wgsl. */ export declare function packFrameUniform(mvp: Mat4, model: Float32Array, cameraPos: [number, number, number], lightDir: [number, number, number]): Float32Array; export interface XRCharacterRendererOptions { lightDir?: [number, number, number]; clear?: [number, number, number, number]; /** Color format the projection layer accepts (Quest is typically 'bgra8unorm'). */ colorFormat?: GPUTextureFormat; } /** * Drives the skinned-character pipeline into a WebXR headset via XRWebGPUBinding. Build once per * session; `start()` runs the per-frame, per-eye loop. The resource build DUPLICATES * renderCharacter's pattern (renderCharacter stays the untouched headless floor). */ export declare class XRCharacterRenderer { private readonly device; private readonly host; private session; private binding; private layer; private baseRef; private colorFormat; private readonly light; private readonly clear; private module; private frameBGL; private matBGL; private pipelineLayout; private pipelineCache; private geo; private jointBuf; private matBufs; private eyes; constructor(device: GPUDevice, host: CharacterHost, opts?: XRCharacterRendererOptions); /** Begin an immersive-vr session and start the per-eye render loop. ON-DEVICE only. */ start(): Promise; private onFrame; private normalizeGroups; private buildResources; private eyeResources; private getPipeline; private matBindGroup; /** Destroy GPU resources + drop the session. Auto-called on session 'end'. */ dispose(): void; } //# sourceMappingURL=character-render-xr.d.ts.map