@vincentt-xr/sdk 2.0.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (159) hide show
  1. package/GROUNDING.md +537 -0
  2. package/LICENSE +7 -0
  3. package/README.md +85 -0
  4. package/dist/DebuggerUI-CEfdddkZ.cjs +1 -0
  5. package/dist/DebuggerUI-Dgop6Q6o.js +269 -0
  6. package/dist/audio/AudioEngine.d.ts +98 -0
  7. package/dist/audio/index.d.ts +34 -0
  8. package/dist/components/AspectRatioContainer/index.d.ts +10 -0
  9. package/dist/components/BodyTracker/index.d.ts +15 -0
  10. package/dist/components/Debugger/DebuggerProvider.d.ts +22 -0
  11. package/dist/components/Debugger/DebuggerUI.d.ts +13 -0
  12. package/dist/components/Debugger/index.d.ts +38 -0
  13. package/dist/components/Debugger/styles.d.ts +19 -0
  14. package/dist/components/FaceMesh/FaceMesh.d.ts +26 -0
  15. package/dist/components/FaceMesh/canonical/CanonicalFaceMeshRenderer.d.ts +34 -0
  16. package/dist/components/FaceMesh/canonical/parseCanonicalFaceModel.d.ts +16 -0
  17. package/dist/components/FaceMesh/canonical/useCanonicalFaceMesh.d.ts +15 -0
  18. package/dist/components/FaceMesh/deform.d.ts +36 -0
  19. package/dist/components/FaceMesh/index.d.ts +6 -0
  20. package/dist/components/FaceMesh/indices.d.ts +1 -0
  21. package/dist/components/FaceMesh/material/blendModes.d.ts +2 -0
  22. package/dist/components/FaceMesh/material/defaults.d.ts +3 -0
  23. package/dist/components/FaceMesh/material/index.d.ts +5 -0
  24. package/dist/components/FaceMesh/material/options.d.ts +25 -0
  25. package/dist/components/FaceMesh/material/support.d.ts +3 -0
  26. package/dist/components/FaceMesh/material/types.d.ts +23 -0
  27. package/dist/components/FaceMesh/uv.d.ts +1 -0
  28. package/dist/components/FaceRetouch/Background.d.ts +16 -0
  29. package/dist/components/FaceRetouch/index.d.ts +6 -0
  30. package/dist/components/FaceRetouch/landmarkMask.d.ts +23 -0
  31. package/dist/components/FaceRetouch/retouchRegions.d.ts +23 -0
  32. package/dist/components/FaceRetouch/useFaceRetouchMask.d.ts +14 -0
  33. package/dist/components/FaceRetouch/useFaceRetouchRegions.d.ts +12 -0
  34. package/dist/components/FaceTracker/BoundingBoxOverlay.d.ts +20 -0
  35. package/dist/components/FaceTracker/index.d.ts +54 -0
  36. package/dist/components/GestureTracker/index.d.ts +31 -0
  37. package/dist/components/GestureTrigger/index.d.ts +3 -0
  38. package/dist/components/HandTracker/index.d.ts +24 -0
  39. package/dist/components/HeadBinding/index.d.ts +31 -0
  40. package/dist/components/HeadBindingOccluder/index.d.ts +36 -0
  41. package/dist/components/HeadOccluder/index.d.ts +13 -0
  42. package/dist/components/Panel/index.d.ts +71 -0
  43. package/dist/components/PerspectiveCamera/index.d.ts +14 -0
  44. package/dist/components/ScreenSpaceUI/ScreenTransform.d.ts +54 -0
  45. package/dist/components/ScreenSpaceUI/context.d.ts +29 -0
  46. package/dist/components/ScreenSpaceUI/index.d.ts +40 -0
  47. package/dist/components/Segmentation/index.d.ts +44 -0
  48. package/dist/components/SpriteAnimation/index.d.ts +52 -0
  49. package/dist/components/TextLabel/index.d.ts +62 -0
  50. package/dist/components/TrackingAnchor/index.d.ts +74 -0
  51. package/dist/components/VideoBackground/index.d.ts +38 -0
  52. package/dist/components/XRCompositor/index.d.ts +5 -0
  53. package/dist/components/XRDebugView/index.d.ts +6 -0
  54. package/dist/components/XRLayer/index.d.ts +6 -0
  55. package/dist/components/XRMediaSurface/index.d.ts +27 -0
  56. package/dist/components/XRProvider/index.d.ts +13 -0
  57. package/dist/components/XRScene/defaults.d.ts +4 -0
  58. package/dist/components/XRScene/index.d.ts +15 -0
  59. package/dist/components/XRViewport/index.d.ts +101 -0
  60. package/dist/components/index.d.ts +26 -0
  61. package/dist/config/index.d.ts +8 -0
  62. package/dist/constants/index.d.ts +25 -0
  63. package/dist/constants/renderLayers.d.ts +25 -0
  64. package/dist/entries/all.d.ts +15 -0
  65. package/dist/entries/core.d.ts +21 -0
  66. package/dist/entries/face-effects.d.ts +19 -0
  67. package/dist/entries/internal.d.ts +16 -0
  68. package/dist/entries/low-level.d.ts +30 -0
  69. package/dist/entries/tracking.d.ts +15 -0
  70. package/dist/face-effects.cjs +252 -0
  71. package/dist/face-effects.js +3542 -0
  72. package/dist/hasFullUnitUVBounds-BGvcFsQM.js +26 -0
  73. package/dist/hasFullUnitUVBounds-p1Dl0ejX.cjs +1 -0
  74. package/dist/hooks/faceResults.d.ts +39 -0
  75. package/dist/hooks/selectors.d.ts +33 -0
  76. package/dist/hooks/useCalibrationFaceTracker.d.ts +23 -0
  77. package/dist/hooks/useDebugger/index.d.ts +25 -0
  78. package/dist/hooks/useDebugger/types.d.ts +20 -0
  79. package/dist/hooks/useFaceBoundingBox.d.ts +11 -0
  80. package/dist/hooks/useFaceResults.d.ts +31 -0
  81. package/dist/hooks/useGestureEdge.d.ts +53 -0
  82. package/dist/hooks/useMediaRecorder.d.ts +40 -0
  83. package/dist/hooks/useTrackerContext.d.ts +35 -0
  84. package/dist/hooks/useXRModel.d.ts +15 -0
  85. package/dist/hooks/useXRSession/constants.d.ts +4 -0
  86. package/dist/hooks/useXRSession/facade.d.ts +39 -0
  87. package/dist/hooks/useXRSession/fns.d.ts +5 -0
  88. package/dist/hooks/useXRSession/index.d.ts +4 -0
  89. package/dist/hooks/useXRSession/registry.d.ts +52 -0
  90. package/dist/hooks/useXRSession/store.d.ts +40 -0
  91. package/dist/index-B5J4gzn2.cjs +1 -0
  92. package/dist/index-BD-JWMjE.js +1991 -0
  93. package/dist/index-BVBVg96G.cjs +1 -0
  94. package/dist/index-CYMj26Ej.js +1331 -0
  95. package/dist/index-DtwHElmG.js +157 -0
  96. package/dist/index-PtFmD6B8.cjs +1 -0
  97. package/dist/internal-DH5d1Xnq.cjs +1 -0
  98. package/dist/internal-KOKJDxCG.js +519 -0
  99. package/dist/internal.cjs +1 -0
  100. package/dist/internal.js +14 -0
  101. package/dist/low-level.cjs +1 -0
  102. package/dist/low-level.js +941 -0
  103. package/dist/main.cjs +1 -0
  104. package/dist/main.js +612 -0
  105. package/dist/models/Base/index.d.ts +25 -0
  106. package/dist/models/Body/index.d.ts +22 -0
  107. package/dist/models/Face/constants.d.ts +2 -0
  108. package/dist/models/Face/index.d.ts +45 -0
  109. package/dist/models/Face/landmarksData.d.ts +2 -0
  110. package/dist/models/Hand/GestureTracking.d.ts +21 -0
  111. package/dist/models/Hand/HandTracking.d.ts +21 -0
  112. package/dist/models/Segmentation/index.d.ts +75 -0
  113. package/dist/models/index.d.ts +5 -0
  114. package/dist/modules/XRClient/index.d.ts +9 -0
  115. package/dist/modules/index.d.ts +1 -0
  116. package/dist/selectors-BHO6TnoC.js +59 -0
  117. package/dist/selectors-Bub0o3qy.cjs +1 -0
  118. package/dist/services/ApiService.d.ts +12 -0
  119. package/dist/services/MetricsCollector/CameraFPSTracker.d.ts +25 -0
  120. package/dist/services/MetricsCollector/MemoryTracker.d.ts +43 -0
  121. package/dist/services/MetricsCollector/RenderTimeTracker.d.ts +10 -0
  122. package/dist/services/MetricsCollector/ResolutionTracker.d.ts +26 -0
  123. package/dist/services/MetricsCollector/index.d.ts +59 -0
  124. package/dist/services/MetricsCollector/types.d.ts +47 -0
  125. package/dist/services/MetricsCollector/utils.d.ts +65 -0
  126. package/dist/texture/computeContainScale.d.ts +25 -0
  127. package/dist/texture/hasFullUnitUVBounds.d.ts +37 -0
  128. package/dist/texture/types.d.ts +20 -0
  129. package/dist/tracking.cjs +1 -0
  130. package/dist/tracking.js +344 -0
  131. package/dist/types/body.d.ts +3 -0
  132. package/dist/types/client.d.ts +3 -0
  133. package/dist/types/common.d.ts +9 -0
  134. package/dist/types/compositor.d.ts +23 -0
  135. package/dist/types/debugger.d.ts +83 -0
  136. package/dist/types/face.d.ts +67 -0
  137. package/dist/types/gesture-tracking.d.ts +15 -0
  138. package/dist/types/hand-tracking.d.ts +5 -0
  139. package/dist/types/headBinding.d.ts +67 -0
  140. package/dist/types/index.d.ts +12 -0
  141. package/dist/types/logger.d.ts +4 -0
  142. package/dist/types/model.d.ts +46 -0
  143. package/dist/types/nodes.d.ts +35 -0
  144. package/dist/types/segmentation.d.ts +31 -0
  145. package/dist/types/session.d.ts +102 -0
  146. package/dist/types/tracking.d.ts +30 -0
  147. package/dist/types/util-types.d.ts +1 -0
  148. package/dist/useFaceResults-cpsSmKKc.js +81 -0
  149. package/dist/useFaceResults-hVUJYSEY.cjs +1 -0
  150. package/dist/utils/calibrationDebug.d.ts +9 -0
  151. package/dist/utils/dataURL.d.ts +6 -0
  152. package/dist/utils/drawMediaCover.d.ts +18 -0
  153. package/dist/utils/errors.d.ts +3 -0
  154. package/dist/utils/fns.d.ts +48 -0
  155. package/dist/utils/headBinding.d.ts +85 -0
  156. package/dist/utils/integrity.d.ts +43 -0
  157. package/dist/utils/landmarkBounds.d.ts +11 -0
  158. package/dist/utils/logger.d.ts +7 -0
  159. package/package.json +113 -0
@@ -0,0 +1,2 @@
1
+ export declare const FACE_OCCLUDER_SCALE_FACTOR = 0.11;
2
+ export declare const FACE_OCCLUDER_Y_ROTATION_OFFSET_SCALE_FACTOR = 0.004;
@@ -0,0 +1,45 @@
1
+ import { NormalizedLandmark } from '@mediapipe/tasks-vision';
2
+ import { XRModelNodeFaceTracking } from '../../types/nodes';
3
+ import { RunModelParams } from '../../types';
4
+ import { PerformanceData } from '../../types/common';
5
+ import { FaceModelOptions } from '../../types/face';
6
+ import { BaseXRModel } from '../Base';
7
+ export declare class FaceTrackingModel extends BaseXRModel {
8
+ private landmarker;
9
+ private processingTime;
10
+ private sourceCanvas;
11
+ private analysisCanvas;
12
+ private getSource;
13
+ private detectionResults;
14
+ private numFaces;
15
+ private cameras;
16
+ private faces;
17
+ private leftCheekScratch;
18
+ private rightCheekScratch;
19
+ private landmarkScratch;
20
+ private rotMatrixScratch;
21
+ private rotQuatScratch;
22
+ private rotEulerScratch;
23
+ constructor();
24
+ private landmarkForSource;
25
+ private extractAndUpdateFaceData;
26
+ private processFaceTracking;
27
+ resume(): void;
28
+ private getFace;
29
+ private getDetectionResults;
30
+ private getRawFaceTrackingData;
31
+ initialize(options?: FaceModelOptions): Promise<void>;
32
+ run({ sourceCanvas, getSource, targetFps }: RunModelParams): Promise<void>;
33
+ getModelNode(): XRModelNodeFaceTracking;
34
+ getPerformanceData(): Promise<PerformanceData>;
35
+ }
36
+ export declare const resolveFaceYawRotation: (yawDegrees: number) => number;
37
+ export declare const resolveFaceAnalysisDimension: (numFaces: number) => 1024 | 512;
38
+ /**
39
+ * Reference (allocating) source-aware landmark normalization. Non-webcam
40
+ * sources (image/video) read mirrored from MediaPipe, so x is flipped to
41
+ * display space. The per-frame extraction path uses an in-place scratch
42
+ * variant (`landmarkForSource`) to avoid allocating; this pure form exists
43
+ * for callers/tests that need a plain array transform.
44
+ */
45
+ export declare const normalizeFaceLandmarksForSource: (landmarks: NormalizedLandmark[], sourceKind?: "webcam" | "image" | "video") => NormalizedLandmark[];
@@ -0,0 +1,2 @@
1
+ declare const DEMO_LANDMARKS: number[];
2
+ export default DEMO_LANDMARKS;
@@ -0,0 +1,21 @@
1
+ import { XRModelNodeGestureTracking } from '../../types/nodes';
2
+ import { RunModelParams } from '../../types';
3
+ import { PerformanceData } from '../../types/common';
4
+ import { BaseXRModel } from '../Base';
5
+ export declare class GestureTrackingModel extends BaseXRModel {
6
+ private landmarker;
7
+ private processingTime;
8
+ private coordinates;
9
+ private gesture;
10
+ private sourceCanvas;
11
+ private readonly downscaler;
12
+ constructor();
13
+ private getGestureData;
14
+ private processGestureTracking;
15
+ resume(): void;
16
+ dispose(): void;
17
+ initialize(): Promise<void>;
18
+ run({ sourceCanvas, targetFps }: RunModelParams): Promise<void>;
19
+ getModelNode(): XRModelNodeGestureTracking;
20
+ getPerformanceData(): Promise<PerformanceData>;
21
+ }
@@ -0,0 +1,21 @@
1
+ import { XRModelNodeHandTracking } from '../../types/nodes';
2
+ import { RunModelParams } from '../../types';
3
+ import { PerformanceData } from '../../types/common';
4
+ import { BaseXRModel } from '../Base';
5
+ export declare class HandTrackingModel extends BaseXRModel {
6
+ private landmarker;
7
+ private processingTime;
8
+ private coordinates;
9
+ private gesture;
10
+ private sourceCanvas;
11
+ private readonly downscaler;
12
+ constructor();
13
+ private getHandData;
14
+ private processHandTracking;
15
+ resume(): void;
16
+ dispose(): void;
17
+ initialize(): Promise<void>;
18
+ run({ sourceCanvas, targetFps }: RunModelParams): Promise<void>;
19
+ getModelNode(): XRModelNodeHandTracking;
20
+ getPerformanceData(): Promise<PerformanceData>;
21
+ }
@@ -0,0 +1,75 @@
1
+ import { PerformanceData, RunModelParams, SegmentationModelOptions } from '../../types';
2
+ import { XRModelNodeSegmentation } from '../../types/nodes';
3
+ import { BaseXRModel } from '../Base';
4
+ export declare class BackgroundSegmentationModel extends BaseXRModel {
5
+ private segmenter;
6
+ private processingTime;
7
+ private sourceCanvas;
8
+ private processCanvas;
9
+ private filterCanvas;
10
+ private inputSource;
11
+ private inputSourceSize;
12
+ private glCanvas;
13
+ private drawingUtils;
14
+ private useGpuMaskPath;
15
+ private maskImageData;
16
+ private maskCanvas;
17
+ private segmentationMaskTexture;
18
+ private isMaskSetup;
19
+ private isProcessing;
20
+ private latestMask;
21
+ private rawCache;
22
+ private quality;
23
+ constructor();
24
+ private getQualityScaleFactor;
25
+ /**
26
+ * Set (or clear) a high-resolution input override. Pass the raw <video>/<img>
27
+ * (or any CanvasImageSource with intrinsic dimensions) to run segmentation on
28
+ * native-resolution, uncropped frames instead of the small display-fit session
29
+ * feed. Pass `undefined` to revert to the shared feed canvas.
30
+ */
31
+ setInputSource(source: CanvasImageSource | undefined): void;
32
+ private readIntrinsicSize;
33
+ /**
34
+ * Size the process canvas to the override input's aspect ratio, bounded by
35
+ * PROCESS_MAX_DIM on the long edge, and keep the GL canvas in sync so the GPU
36
+ * mask renders at the same resolution. No-op when there is no override, or when
37
+ * the intrinsic size hasn't changed since the last frame.
38
+ */
39
+ private ensureProcessCanvasForInput;
40
+ private processSegmentation;
41
+ /**
42
+ * Blit the GPU-rendered mask (already RGBA-inverted by drawCategoryMask)
43
+ * straight from the GL canvas into the mask canvas, cover-fitted through the
44
+ * soft-edge blur. `drawImage(glCanvas)` is a GPU→GPU transfer — no readPixels,
45
+ * no CPU array, no ImageData, no row flip (the 2D canvas presents the WebGL
46
+ * canvas right-side-up). This is the zero-readback path.
47
+ */
48
+ private blitGlToMask;
49
+ /**
50
+ * CPU-fallback inverted-alpha ImageData build (only when the GPU path is off).
51
+ * The single-channel mask is expanded to RGBA with the person→transparent,
52
+ * background→opaque convention (green carries the signal for the alphaMap).
53
+ */
54
+ private readMaskToImageData;
55
+ /**
56
+ * CPU-fallback blit: put the inverted-alpha mask ImageData into maskCanvas
57
+ * with a soft-edge blur, cover-fitted to the render target. Only used when the
58
+ * GPU path is off; the GPU path blits the GL canvas directly (blitGlToMask).
59
+ */
60
+ private blitImageDataToMask;
61
+ private stagingCanvas;
62
+ private getStagingCanvas;
63
+ resume(): void;
64
+ dispose(): void;
65
+ initialize(options?: SegmentationModelOptions): Promise<void>;
66
+ run({ sourceCanvas, renderWidth, renderHeight, targetFps, }: RunModelParams): Promise<void>;
67
+ /**
68
+ * Lazily read the single-channel mask back to a Uint8Array. Only invoked when
69
+ * a consumer calls getRawSegmentationData(); the default texture path never
70
+ * touches it, so apps that only use <VideoBackground> pay no extra readback.
71
+ */
72
+ private getRawSegmentationData;
73
+ getModelNode(): XRModelNodeSegmentation;
74
+ getPerformanceData(): Promise<PerformanceData>;
75
+ }
@@ -0,0 +1,5 @@
1
+ export { BodyTrackingModel } from './Body';
2
+ export { FaceTrackingModel } from './Face';
3
+ export { GestureTrackingModel } from './Hand/GestureTracking';
4
+ export { HandTrackingModel } from './Hand/HandTracking';
5
+ export { BackgroundSegmentationModel } from './Segmentation';
@@ -0,0 +1,9 @@
1
+ import { XRClientConfig } from '../../types';
2
+ export declare class XRClient {
3
+ private static instance;
4
+ private logger;
5
+ private session?;
6
+ static initialize(config: XRClientConfig): Promise<XRClient>;
7
+ private constructor();
8
+ createSession(): Promise<XRSession>;
9
+ }
@@ -0,0 +1 @@
1
+ export * from './XRClient';
@@ -0,0 +1,59 @@
1
+ import { useSyncExternalStore as s, useMemo as a } from "react";
2
+ import { u } from "./index-CYMj26Ej.js";
3
+ const r = () => u().session.store, o = (e) => (t) => e.subscribe(t), p = () => {
4
+ const e = r();
5
+ return s(
6
+ o(e),
7
+ () => e.getSnapshot().ready,
8
+ () => !1
9
+ );
10
+ }, l = () => {
11
+ const e = r();
12
+ return s(
13
+ o(e),
14
+ () => e.getSnapshot().error,
15
+ () => {
16
+ }
17
+ );
18
+ }, d = () => {
19
+ const e = r();
20
+ return s(
21
+ o(e),
22
+ () => e.getSnapshot().cameraTexture,
23
+ () => {
24
+ }
25
+ );
26
+ }, h = () => {
27
+ const e = r(), t = s(
28
+ o(e),
29
+ () => e.getSnapshot().renderWidth,
30
+ () => 0
31
+ ), n = s(
32
+ o(e),
33
+ () => e.getSnapshot().renderHeight,
34
+ () => 0
35
+ );
36
+ return a(() => ({ width: t, height: n }), [t, n]);
37
+ }, S = (e) => {
38
+ const t = r(), n = s(
39
+ o(t),
40
+ () => t.getSnapshot().pipeline.get(e) ?? null,
41
+ () => null
42
+ );
43
+ return a(() => n ? n.getModelNode() : null, [n]);
44
+ }, g = () => {
45
+ const e = r(), t = s(
46
+ o(e),
47
+ () => e.getSnapshot().pipeline,
48
+ () => e.getSnapshot().pipeline
49
+ );
50
+ return a(() => Array.from(t.keys()), [t]);
51
+ };
52
+ export {
53
+ S as a,
54
+ p as b,
55
+ l as c,
56
+ h as d,
57
+ g as e,
58
+ d as u
59
+ };
@@ -0,0 +1 @@
1
+ "use strict";const s=require("react"),u=require("./index-PtFmD6B8.cjs"),o=()=>u.useXRContext().session.store,n=e=>t=>e.subscribe(t),c=()=>{const e=o();return s.useSyncExternalStore(n(e),()=>e.getSnapshot().ready,()=>!1)},a=()=>{const e=o();return s.useSyncExternalStore(n(e),()=>e.getSnapshot().error,()=>{})},i=()=>{const e=o();return s.useSyncExternalStore(n(e),()=>e.getSnapshot().cameraTexture,()=>{})},S=()=>{const e=o(),t=s.useSyncExternalStore(n(e),()=>e.getSnapshot().renderWidth,()=>0),r=s.useSyncExternalStore(n(e),()=>e.getSnapshot().renderHeight,()=>0);return s.useMemo(()=>({width:t,height:r}),[t,r])},l=e=>{const t=o(),r=s.useSyncExternalStore(n(t),()=>t.getSnapshot().pipeline.get(e)??null,()=>null);return s.useMemo(()=>r?r.getModelNode():null,[r])},p=()=>{const e=o(),t=s.useSyncExternalStore(n(e),()=>e.getSnapshot().pipeline,()=>e.getSnapshot().pipeline);return s.useMemo(()=>Array.from(t.keys()),[t])};exports.useXRCameraTexture=i;exports.useXRError=a;exports.useXRModelNode=l;exports.useXRPipelineSnapshot=p;exports.useXRReady=c;exports.useXRRenderSize=S;
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Wrapper class for making API requests.
3
+ */
4
+ export declare class ApiService {
5
+ private baseUrl;
6
+ private apiKey;
7
+ constructor(params: {
8
+ baseUrl: string;
9
+ apiKey: string;
10
+ });
11
+ fetch<T = unknown>(url: string, options?: RequestInit): Promise<T>;
12
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Camera FPS Tracker
3
+ * Tracks frames per second from the camera/video processing loop
4
+ * Updates every 500ms as specified in PRD
5
+ */
6
+ export declare class CameraFPSTracker {
7
+ private frameTimestamps;
8
+ private lastUpdateTime;
9
+ private currentFPS;
10
+ private readonly updateInterval;
11
+ constructor();
12
+ /**
13
+ * Track a new frame
14
+ * Should be called on each camera frame from renderVideo loop
15
+ */
16
+ trackFrame(): void;
17
+ /**
18
+ * Get current FPS value
19
+ */
20
+ getFPS(): number;
21
+ /**
22
+ * Reset tracker state
23
+ */
24
+ reset(): void;
25
+ }
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Memory Tracker
3
+ * Tracks JavaScript heap memory usage via performance.memory API
4
+ * Updates every 1 second as specified in PRD
5
+ * Gracefully handles browsers that don't support performance.memory (non-Chrome)
6
+ */
7
+ export interface MemoryUsage {
8
+ used: number;
9
+ total: number;
10
+ percentage: number;
11
+ }
12
+ export declare class MemoryTracker {
13
+ private intervalId;
14
+ private memoryUsage;
15
+ private readonly updateInterval;
16
+ private isSupported;
17
+ constructor(updateInterval?: number);
18
+ /**
19
+ * Check if performance.memory is supported
20
+ */
21
+ private checkSupport;
22
+ /**
23
+ * Start tracking memory usage
24
+ */
25
+ start(): void;
26
+ /**
27
+ * Stop tracking memory usage
28
+ */
29
+ stop(): void;
30
+ /**
31
+ * Update memory measurements
32
+ */
33
+ private updateMemory;
34
+ /**
35
+ * Get current memory usage
36
+ * Returns null if performance.memory is not supported
37
+ */
38
+ getMemoryUsage(): MemoryUsage | null;
39
+ /**
40
+ * Check if memory tracking is supported
41
+ */
42
+ isMemorySupported(): boolean;
43
+ }
@@ -0,0 +1,10 @@
1
+ import { RenderTimeCallback } from './types';
2
+ export interface RenderTimeTrackerProps {
3
+ /** Callback function to receive render time measurements */
4
+ onUpdate: RenderTimeCallback;
5
+ }
6
+ /**
7
+ * Hidden component that tracks rendering performance
8
+ * Place this inside your XRScene to enable render time tracking
9
+ */
10
+ export declare function RenderTimeTracker({ onUpdate }: RenderTimeTrackerProps): null;
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Resolution Tracker
3
+ * Tracks the active camera stream resolution from the video element
4
+ * Updates when video metadata is loaded or dimensions change
5
+ */
6
+ export declare class ResolutionTracker {
7
+ private resolution;
8
+ private videoElement;
9
+ private metadataListener;
10
+ /**
11
+ * Start tracking resolution from a video element
12
+ */
13
+ start(videoElement: HTMLVideoElement | null): void;
14
+ /**
15
+ * Stop tracking and clean up listeners
16
+ */
17
+ stop(): void;
18
+ /**
19
+ * Update resolution from video element
20
+ */
21
+ private updateResolution;
22
+ /**
23
+ * Get current resolution string (e.g., "1280x720")
24
+ */
25
+ getResolution(): string;
26
+ }
@@ -0,0 +1,59 @@
1
+ import { DebuggerMetrics } from '../../types/debugger';
2
+ import { MetricsCollectorOptions } from './types';
3
+ export declare class MetricsCollector {
4
+ private options;
5
+ private isRunning;
6
+ private metrics;
7
+ private cameraFPSTracker;
8
+ private memoryTracker;
9
+ private resolutionTracker;
10
+ private frameTimes;
11
+ private lastEffectiveFPSUpdate;
12
+ constructor(options?: MetricsCollectorOptions);
13
+ /**
14
+ * Start collecting metrics
15
+ * @param videoElement Optional video element for resolution tracking
16
+ */
17
+ start(videoElement?: HTMLVideoElement | null): void;
18
+ /**
19
+ * Stop collecting metrics and clean up
20
+ */
21
+ stop(): void;
22
+ /**
23
+ * Setup global hook for camera FPS tracking
24
+ * This allows useXRSession to call trackFrame() without tight coupling
25
+ */
26
+ private setupCameraFPSHook;
27
+ /**
28
+ * Cleanup global hook
29
+ */
30
+ private cleanupCameraFPSHook;
31
+ /**
32
+ * Get current metrics snapshot
33
+ * Updates metrics from all trackers before returning
34
+ */
35
+ getMetrics(): DebuggerMetrics;
36
+ /**
37
+ * Update metrics from all trackers
38
+ */
39
+ private updateMetricsFromTrackers;
40
+ /**
41
+ * Update render time (called from RenderTimeTracker component)
42
+ */
43
+ updateRenderTime(renderTime: number): void;
44
+ /**
45
+ * Update detection time from models
46
+ * Aggregates processing time from all active models in the XR pipeline
47
+ */
48
+ updateDetectionTime(pipeline?: Partial<Record<string, any>>): Promise<void>;
49
+ /**
50
+ * Update effective FPS calculation
51
+ * (will be implemented in Phase 6)
52
+ */
53
+ private updateEffectiveFPS;
54
+ /**
55
+ * Check if collector is running
56
+ */
57
+ isActive(): boolean;
58
+ }
59
+ export default MetricsCollector;
@@ -0,0 +1,47 @@
1
+ import { DebuggerMetrics } from '../../types/debugger';
2
+ /**
3
+ * Memory information from performance.memory API (Chrome-specific)
4
+ */
5
+ export interface PerformanceMemory {
6
+ /** Used JavaScript heap size in bytes */
7
+ usedJSHeapSize: number;
8
+ /** Total allocated heap size in bytes */
9
+ totalJSHeapSize: number;
10
+ /** JavaScript heap size limit in bytes */
11
+ jsHeapSizeLimit: number;
12
+ }
13
+ /**
14
+ * Extended Performance interface with memory property
15
+ */
16
+ export interface PerformanceWithMemory extends Performance {
17
+ memory?: PerformanceMemory;
18
+ }
19
+ /**
20
+ * Callback type for render time tracking
21
+ */
22
+ export type RenderTimeCallback = (renderTime: number) => void;
23
+ /**
24
+ * Callback type for camera frame tracking
25
+ */
26
+ export type CameraFrameCallback = () => void;
27
+ /**
28
+ * Global window interface extension for debugger hooks
29
+ */
30
+ export interface WindowWithDebuggerHooks extends Window {
31
+ __xr_debugger_metrics?: {
32
+ trackCameraFrame: CameraFrameCallback;
33
+ };
34
+ }
35
+ /**
36
+ * Options for MetricsCollector initialization
37
+ */
38
+ export interface MetricsCollectorOptions {
39
+ /** Whether to enable memory tracking (default: true) */
40
+ enableMemoryTracking?: boolean;
41
+ /** Update interval for memory polling in ms (default: 1000) */
42
+ memoryUpdateInterval?: number;
43
+ }
44
+ /**
45
+ * Partial metrics for incremental updates
46
+ */
47
+ export type PartialMetrics = Partial<DebuggerMetrics>;
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Utility functions for metrics collection
3
+ * Provides efficient data structures and helpers for performance tracking
4
+ */
5
+ /**
6
+ * Efficient circular buffer for rolling averages
7
+ * Uses typed array for better performance
8
+ */
9
+ export declare class CircularBuffer {
10
+ private buffer;
11
+ private index;
12
+ private filled;
13
+ private size;
14
+ constructor(size: number);
15
+ /**
16
+ * Add a value to the buffer
17
+ */
18
+ add(value: number): void;
19
+ /**
20
+ * Get average of all values in buffer
21
+ */
22
+ getAverage(): number;
23
+ /**
24
+ * Get the most recent value
25
+ */
26
+ getLast(): number;
27
+ /**
28
+ * Get number of values currently in buffer
29
+ */
30
+ getCount(): number;
31
+ /**
32
+ * Clear all values from buffer
33
+ */
34
+ clear(): void;
35
+ }
36
+ /**
37
+ * Exponential moving average for smooth value transitions
38
+ * @param currentValue Current smoothed value
39
+ * @param newValue New raw value
40
+ * @param smoothing Smoothing factor (0-1), higher = more smoothing
41
+ */
42
+ export declare function smoothValue(currentValue: number, newValue: number, smoothing?: number): number;
43
+ /**
44
+ * Throttle function to limit execution frequency
45
+ * @param func Function to throttle
46
+ * @param wait Minimum time between executions in milliseconds
47
+ */
48
+ export declare function throttle<T extends (...args: any[]) => any>(func: T, wait: number): (...args: Parameters<T>) => void;
49
+ /**
50
+ * Format number to fixed decimal places
51
+ * @param value Number to format
52
+ * @param decimals Number of decimal places (default: 1)
53
+ */
54
+ export declare function formatNumber(value: number, decimals?: number): string;
55
+ /**
56
+ * Format bytes to megabytes
57
+ * @param bytes Bytes value
58
+ */
59
+ export declare function bytesToMB(bytes: number): number;
60
+ /**
61
+ * Calculate percentage
62
+ * @param value Numerator
63
+ * @param total Denominator
64
+ */
65
+ export declare function percentage(value: number, total: number): number;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Computes the `[sx, sy, sz]` scale factors that, when multiplied into a
3
+ * mesh's scale inside a rect of `rectAspect`, produce a mesh whose rendered
4
+ * aspect equals `textureAspect`. This is the core of `mapFit: "contain"` —
5
+ * instead of transforming the texture's UV matrix (which produces zoom/crop
6
+ * under three.js's default wrap mode), the mesh itself is shrunk on one axis
7
+ * so the texture fills a correctly-shaped plane and the remaining rect area
8
+ * is genuinely empty.
9
+ *
10
+ * Rule:
11
+ * - `rectAspect > textureAspect` → rect is wider than texture →
12
+ * `[textureAspect / rectAspect, 1, 1]` (shrink X, letterbox L/R).
13
+ * - `rectAspect < textureAspect` → rect is taller than texture →
14
+ * `[1, rectAspect / textureAspect, 1]` (shrink Y, letterbox T/B).
15
+ * - `rectAspect === textureAspect` (within 1e-6) → `[1, 1, 1]` (no-op).
16
+ *
17
+ * Pure math — no three.js imports. Safe to call every render.
18
+ *
19
+ * @param rectAspect Aspect (width / height) of the enclosing rect.
20
+ * @param textureAspect Aspect (width / height) of the texture.
21
+ * @returns `[sx, sy, sz]`. `sz` is always `1`; we fit 2D textures to 2D rects.
22
+ * Returns `[1, 1, 1]` for non-positive / non-finite inputs so the
23
+ * caller doesn't have to pre-guard on asset-load state.
24
+ */
25
+ export declare function computeContainScale(rectAspect: number, textureAspect: number): [number, number, number];
@@ -0,0 +1,37 @@
1
+ import * as THREE from "three";
2
+ /**
3
+ * Returns `true` if the `uv` attribute of `geometry` covers exactly the full
4
+ * 0..1 unit square within `tolerance` on each axis.
5
+ *
6
+ * Primitive geometries (`PlaneGeometry`, `BoxGeometry`, etc.) always return
7
+ * `true`. Imported GLTF meshes may return `false` when their UVs have been
8
+ * baked to a sub-region or use tiling coordinates outside [0, 1].
9
+ *
10
+ * This is the fit-eligibility guard used by `mapFit: "contain"` in the
11
+ * xr-client renderer. The v2 mesh-scale fit mechanism assumes the whole
12
+ * plane shows the whole texture — only true when UVs cover the unit square.
13
+ * When this returns `false`, the caller should skip the fit and emit a
14
+ * warning via `logUVBoundsWarningOnce`.
15
+ *
16
+ * @param geometry The geometry to inspect.
17
+ * @param tolerance Epsilon for comparing UV min/max to 0 and 1.
18
+ * Defaults to `0.001`.
19
+ */
20
+ export declare function hasFullUnitUVBounds(geometry: THREE.BufferGeometry, tolerance?: number): boolean;
21
+ /**
22
+ * Emits a deduplicated console warning for a mesh whose UV bounds are not
23
+ * full-unit, so `textureFit` had to fall back to `uvAspect = 1`.
24
+ *
25
+ * Only fires once per `meshId` per session (de-duplicated via module-level
26
+ * Set). Subsequent calls with the same `meshId` are silently ignored.
27
+ *
28
+ * @param meshId A stable identifier for the mesh (e.g. the three.js Object3D `uuid`).
29
+ * @param meshLabel A human-readable label (e.g. the mesh's `name` or `_label`).
30
+ * Falls back to `meshId` if not provided.
31
+ */
32
+ export declare function logUVBoundsWarningOnce(meshId: string, meshLabel?: string): void;
33
+ /**
34
+ * Test helper — resets the deduplicated warning set.
35
+ * Not intended for production use.
36
+ */
37
+ export declare function _resetUVBoundsWarnings(): void;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Supported texture fit modes.
3
+ *
4
+ * - `"fill"` — three.js default; texture is stretched to fill the mesh's UV
5
+ * rectangle. No mesh-scale adjustment is performed.
6
+ * - `"contain"` — the enclosing mesh's rendered scale is adjusted inside its
7
+ * parent rect so the mesh's aspect matches the texture's aspect. The texture
8
+ * then fills a correctly-shaped plane naturally; the remainder of the rect
9
+ * is genuinely empty (nothing drawn). See `computeContainScale`.
10
+ *
11
+ * Implementation note: v2 implements `"contain"` by adjusting the mesh, not
12
+ * by transforming the texture's UV matrix. v1 tried the latter and produced
13
+ * zoom/crop under three.js's default `ClampToEdgeWrapping`.
14
+ */
15
+ export type TextureFit = "fill" | "contain";
16
+ /**
17
+ * Runtime array of all valid TextureFit values.
18
+ * Consumed by editor-ui's type picker and the design agent's approved-types validator.
19
+ */
20
+ export declare const TEXTURE_FITS: readonly TextureFit[];
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const C=require("./useFaceResults-hVUJYSEY.cjs"),b=require("./index-B5J4gzn2.cjs"),E=require("react/jsx-runtime"),S=require("@react-three/fiber"),i=require("react"),z=require("three"),m=require("./index-PtFmD6B8.cjs");function O(e){const r=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(e){for(const t in e)if(t!=="default"){const n=Object.getOwnPropertyDescriptor(e,t);Object.defineProperty(r,t,n.get?n:{enumerable:!0,get:()=>e[t]})}}return r.default=e,Object.freeze(r)}const g=O(z),j={"body.head":0,"body.leftShoulder":11,"body.rightShoulder":12,"body.leftElbow":13,"body.rightElbow":14,"body.leftWrist":15,"body.rightWrist":16,"body.leftHip":23,"body.rightHip":24,"body.leftKnee":25,"body.rightKnee":26,"body.leftAnkle":27,"body.rightAnkle":28},B=({bodyIndex:e=0,active:r=!0,children:t})=>{const n=i.useRef(null),{ready:o,node:d}=b.useXRModel(m.XRModel.BODY_TRACKER,void 0,r),{camera:u}=S.useThree(),l=i.useRef(u);l.current!==u&&(l.current=u);const c=i.useRef(null);S.useFrame(()=>{if(!o||!d||!n.current)return;const p=d;c.current=p;const s=p.getLandmarks2D(e),a=s==null?void 0:s[0];if(!a){n.current.visible=!1;return}const h=x(a,l.current);n.current.visible=!0,n.current.position.copy(h)});const f=i.useCallback(p=>{const s=c.current;if(!s)return null;const a=s.getLandmarks2D(e);if(!a)return null;if(p==="body.neck"){const R=a[11],A=a[12];if(!R||!A)return null;const k={x:(R.x+A.x)/2,y:(R.y+A.y)/2,z:(R.z+A.z)/2};return{position:x(k,l.current)}}const h=j[p];if(h===void 0)return null;const T=a[h];return T?{position:x(T,l.current)}:null},[e]),y=i.useMemo(()=>({type:"body",resolveLandmark:f}),[f]);return E.jsx(b.TrackerContext.Provider,{value:y,children:E.jsx("group",{ref:n,renderOrder:m.RENDER_LAYERS.TRACKED,children:t})})},x=(e,r)=>{const t=new g.Vector3(e.x,e.y,e.z);t.unproject(r);const n=t.sub(r.position).normalize(),o=-r.position.z/n.z;return r.position.clone().add(n.multiplyScalar(o))},H={"hand.wrist":0,"hand.thumbTip":4,"hand.indexTip":8,"hand.middleTip":12,"hand.ringTip":16,"hand.pinkyTip":20,"hand.indexBase":5,"hand.middleBase":9,"hand.ringBase":13,"hand.pinkyBase":17},G=({children:e,targetFps:r,active:t=!0})=>{const n=i.useRef(null),o=i.useMemo(()=>r===void 0?void 0:{targetFps:r},[r]),{ready:d,node:u}=b.useXRModel(m.XRModel.GESTURE_TRACKER,o,t),{camera:l}=S.useThree(),c=i.useRef(l);c.current!==l&&(c.current=l);const f=i.useRef(null);S.useFrame(()=>{var h;if(!d||!u||!n.current)return;f.current=u;const s=(h=u==null?void 0:u.coordinates)==null?void 0:h[0];if(!s){n.current.visible=!1;return}const a=D(s,c.current);n.current.visible=!0,n.current.position.copy(a)});const y=i.useCallback(s=>{var T,R;const a=H[s];if(a===void 0)return null;const h=(R=(T=f.current)==null?void 0:T.coordinates)==null?void 0:R[a];return h?{position:D(h,c.current)}:null},[]),p=i.useMemo(()=>({type:"hand",resolveLandmark:y}),[y]);return E.jsx(b.TrackerContext.Provider,{value:p,children:E.jsx("group",{ref:n,renderOrder:m.RENDER_LAYERS.TRACKED,children:e})})},D=(e,r)=>{const t=new g.Vector3(e.x,e.y,e.z);t.unproject(r);const n=t.sub(r.position).normalize(),o=-r.position.z/n.z;return r.position.clone().add(n.multiplyScalar(o))},K=800,L=200,F=()=>({armed:!1,armStart:null,holdStart:null,fired:!1}),P=(e,{isTrigger:r,gesture:t,now:n,mode:o,debounceMs:d,holdMs:u})=>{if(e.fired)return null;if(o==="hold"){if(r&&t){if(e.holdStart===null&&(e.holdStart=n),n-e.holdStart>=u)return e.fired=!0,t}else e.holdStart=null;return null}return e.armed?r&&t?(e.fired=!0,t):null:(r?e.armStart=null:(e.armStart===null&&(e.armStart=n),n-e.armStart>=d&&(e.armed=!0)),null)};function q({gestures:e,mode:r="arm",debounceMs:t=K,holdMs:n=L,onTrigger:o,enabled:d=!0}){const{ready:u,node:l}=b.useXRModel(m.XRModel.GESTURE_TRACKER),c=i.useRef(o);i.useEffect(()=>{c.current=o},[o]);const f=i.useRef(new Set);i.useEffect(()=>{f.current=new Set(Array.isArray(e)?e:[e])},[e]);const y=i.useRef(F());S.useFrame(()=>{if(!d||!u||!l)return;const p=l.gesture,s=!!(p&&f.current.has(p)),a=P(y.current,{isTrigger:s,gesture:p,now:performance.now(),mode:r,debounceMs:t,holdMs:n});a&&c.current(a)})}const X=e=>(q(e),null),W={"hand.wrist":0,"hand.thumbTip":4,"hand.indexTip":8,"hand.middleTip":12,"hand.ringTip":16,"hand.pinkyTip":20,"hand.indexBase":5,"hand.middleBase":9,"hand.ringBase":13,"hand.pinkyBase":17},V=({children:e,targetFps:r,active:t=!0})=>{const n=i.useRef(null),o=i.useMemo(()=>r===void 0?void 0:{targetFps:r},[r]),{ready:d,node:u}=b.useXRModel(m.XRModel.HAND_TRACKER,o,t),{camera:l}=S.useThree(),c=i.useRef(l);c.current!==l&&(c.current=l);const f=i.useRef(null);S.useFrame(()=>{var T;if(!d||!u||!n.current)return;const s=u;f.current=s;const a=(T=s==null?void 0:s.coordinates)==null?void 0:T[0];if(!a){n.current.visible=!1;return}const h=M(a,c.current);n.current.visible=!0,n.current.position.copy(h)});const y=i.useCallback(s=>{var T,R;const a=W[s];if(a===void 0)return null;const h=(R=(T=f.current)==null?void 0:T.coordinates)==null?void 0:R[a];return h?{position:M(h,c.current)}:null},[]),p=i.useMemo(()=>({type:"hand",resolveLandmark:y}),[y]);return E.jsx(b.TrackerContext.Provider,{value:p,children:E.jsx("group",{ref:n,renderOrder:m.RENDER_LAYERS.TRACKED,children:e})})},M=(e,r)=>{const t=new g.Vector3(e.x,e.y,e.z);t.unproject(r);const n=t.sub(r.position).normalize(),o=-r.position.z/n.z;return r.position.clone().add(n.multiplyScalar(o))},v=["portrait"],Y=({type:e,active:r=!0,children:t})=>(b.useXRModel(m.XRModel.BACKGROUND_SEGMENTATION,{type:e},r),i.useEffect(()=>{v.includes(e)||console.warn(`[Segmentation] unsupported type "${e}"; valid values: ${v.join(", ")}`)},[e]),E.jsx(E.Fragment,{children:t})),$=["face.forehead","face.noseTip","face.chin","face.leftEyeOuter","face.rightEyeOuter","face.leftCheek","face.rightCheek","face.mouthCenter"],U=["hand.wrist","hand.thumbTip","hand.indexTip","hand.middleTip","hand.ringTip","hand.pinkyTip","hand.indexBase","hand.middleBase","hand.ringBase","hand.pinkyBase"],I=["body.head","body.neck","body.leftShoulder","body.rightShoulder","body.leftElbow","body.rightElbow","body.leftWrist","body.rightWrist","body.leftHip","body.rightHip","body.leftKnee","body.rightKnee","body.leftAnkle","body.rightAnkle"],_=e=>e.startsWith("face.")?"face":e.startsWith("hand.")?"hand":e.startsWith("body.")?"body":null,N=(e,r,t)=>r+t*(e-r),w=(e,r)=>1/(1+1/(2*Math.PI*e)/r),J=(e,r,t,n,o,d)=>{if(!e.initialized||t<=0)return e.pos.copy(r),e.prevRaw.copy(r),e.dxHat.set(0,0,0),e.initialized=!0,e;const u=w(d,t),l=["x","y","z"];for(const c of l){const f=(r[c]-e.prevRaw[c])/t,y=N(f,e.dxHat[c],u);e.dxHat[c]=y;const p=n+o*Math.abs(y),s=w(p,t);e.pos[c]=N(r[c],e.pos[c],s),e.prevRaw[c]=r[c]}return e},Q=({target:e,offset:r,smoothing:t=0,children:n})=>{const o=b.useTrackerContext(),d=i.useRef(null),u=i.useRef(!1),l=i.useRef(new g.Vector3),c=i.useRef({pos:new g.Vector3,prevRaw:new g.Vector3,dxHat:new g.Vector3,initialized:!1}),f=_(e),y=o!==null&&f!==null&&o.type!==f,p=o===null,s=p||y||f===null;return i.useEffect(()=>{p?console.warn(`[TrackingAnchor] target "${e}" requires a FaceTracker / HandTracker / BodyTracker ancestor; rendering null.`):y?console.warn(`[TrackingAnchor] target "${e}" namespace does not match parent tracker type "${o==null?void 0:o.type}"; rendering null.`):f===null&&console.warn(`[TrackingAnchor] target "${e}" is not a recognized face/hand/body landmark; rendering null.`)},[e,f,p,y,o==null?void 0:o.type]),S.useFrame((a,h)=>{if(s||!d.current||!o)return;const T=o.resolveLandmark(e);if(!T){d.current.visible=!1,u.current=!1,c.current.initialized=!1;return}d.current.visible=!0;const R=l.current.copy(T.position),A=d.current.parent;if(A){A.updateMatrixWorld();const k=new g.Matrix4().copy(A.matrixWorld).invert();R.applyMatrix4(k)}if(r&&(R.x+=r[0],R.y+=r[1],R.z+=r[2]),t>0){const k=t*.1;J(c.current,R,u.current?h:0,k,.5,1),d.current.position.copy(c.current.pos)}else d.current.position.copy(R);u.current=!0,T.quaternion&&d.current.quaternion.copy(T.quaternion)}),s?null:E.jsx("group",{ref:d,renderOrder:m.RENDER_LAYERS.TRACKED,children:n})};exports.useFaceResults=C.useFaceResults;exports.FaceMesh=b.FaceMesh;exports.FaceTracker=b.FaceTracker;exports.BODY_TARGETS=I;exports.BodyTracker=B;exports.FACE_TARGETS=$;exports.GestureTracker=G;exports.GestureTrigger=X;exports.HAND_TARGETS=U;exports.HandTracker=V;exports.SEGMENTATION_TYPES=v;exports.Segmentation=Y;exports.TrackingAnchor=Q;exports.getTargetNamespace=_;