@vincentt-xr/sdk 2.0.0-alpha.7 → 2.0.0-alpha.8

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 (275) hide show
  1. package/GROUNDING.md +1109 -13
  2. package/dist/{DebuggerUI-BjOMr8q_.js → DebuggerUI-C-ldiozL.js} +1 -1
  3. package/dist/{DebuggerUI-B6bP6P9r.cjs → DebuggerUI-CWX5EtQv.cjs} +1 -1
  4. package/dist/FaceMeshRenderer-BEEXZwS6.cjs +158 -0
  5. package/dist/FaceMeshRenderer-UuH5sTXG.js +1322 -0
  6. package/dist/FaceRetouch-C7h7x9kd.js +683 -0
  7. package/dist/FaceRetouch-DqftT26Y.cjs +134 -0
  8. package/dist/GLTFLoader-C5q63sKO.js +1633 -0
  9. package/dist/GLTFLoader-Cb_CRwmG.cjs +1 -0
  10. package/dist/SegmentationOverlay-DQuW3dsc.js +133 -0
  11. package/dist/SegmentationOverlay-aWVod8Kl.cjs +1 -0
  12. package/dist/assets/cache.d.ts +99 -0
  13. package/dist/assets/estimate.d.ts +11 -0
  14. package/dist/assets/index.d.ts +7 -0
  15. package/dist/assets/loaders.d.ts +28 -0
  16. package/dist/assets/react.d.ts +33 -0
  17. package/dist/calibration/calibration.d.ts +70 -0
  18. package/dist/calibration/index.d.ts +6 -0
  19. package/dist/calibration/storage.d.ts +13 -0
  20. package/dist/calibration/types.d.ts +53 -0
  21. package/dist/calibration/useXRCalibration.d.ts +46 -0
  22. package/dist/camera/CameraPermissionGate.d.ts +26 -0
  23. package/dist/camera/devices.d.ts +26 -0
  24. package/dist/camera/index.d.ts +8 -0
  25. package/dist/camera/permission.d.ts +86 -0
  26. package/dist/camera/useCameraPermission.d.ts +35 -0
  27. package/dist/capabilities/detect.d.ts +45 -0
  28. package/dist/capabilities/index.d.ts +5 -0
  29. package/dist/capabilities/types.d.ts +120 -0
  30. package/dist/capabilities/useXRCapabilities.d.ts +18 -0
  31. package/dist/compat/environment.d.ts +5 -0
  32. package/dist/compat/index.d.ts +4 -0
  33. package/dist/compat/run.d.ts +18 -0
  34. package/dist/compat/scenarios.d.ts +10 -0
  35. package/dist/compat/types.d.ts +101 -0
  36. package/dist/components/BodyTracker/index.d.ts +9 -0
  37. package/dist/components/FaceMesh/canonical/CanonicalFaceMeshRenderer.d.ts +33 -3
  38. package/dist/components/FaceMesh/canonical/parseCanonicalFaceModel.d.ts +12 -0
  39. package/dist/components/FaceMesh/canonical/shaders.d.ts +1 -1
  40. package/dist/components/FaceMesh/index.d.ts +1 -1
  41. package/dist/components/GestureListener/index.d.ts +11 -0
  42. package/dist/components/HandTracker/index.d.ts +10 -0
  43. package/dist/components/HolisticTracker/index.d.ts +69 -0
  44. package/dist/components/HolisticTracker/settings.d.ts +58 -0
  45. package/dist/components/HolisticTracker/signals.d.ts +49 -0
  46. package/dist/components/IrisEffect/IrisMaterial.d.ts +73 -0
  47. package/dist/components/IrisEffect/index.d.ts +51 -0
  48. package/dist/components/IrisEffect/settings.d.ts +117 -0
  49. package/dist/components/LipEffect/LipEffect.d.ts +7 -1
  50. package/dist/components/LipEffect/LipEffectMaterial.d.ts +43 -7
  51. package/dist/components/LipEffect/LipEffects.d.ts +9 -0
  52. package/dist/components/LipEffect/defaults.d.ts +27 -4
  53. package/dist/components/LipEffect/index.d.ts +11 -3
  54. package/dist/components/LipEffect/settings.d.ts +271 -0
  55. package/dist/components/LipEffect/types.d.ts +56 -9
  56. package/dist/components/LipEffect/useLipDesignTextures.d.ts +11 -0
  57. package/dist/components/LipEffect/uvGuide.d.ts +59 -0
  58. package/dist/components/PersonCutout/index.d.ts +50 -0
  59. package/dist/components/PersonCutout/personCutout.d.ts +16 -0
  60. package/dist/components/ScreenImage/components/ScreenImageBody.d.ts +1 -1
  61. package/dist/components/ScreenImage/index.d.ts +3 -1
  62. package/dist/components/ScreenImage/materials/ScreenImageBlendMaterial.d.ts +1 -1
  63. package/dist/components/ScreenImage/materials/ScreenImageMaskMaterial.d.ts +11 -0
  64. package/dist/components/ScreenImage/source.d.ts +6 -0
  65. package/dist/components/ScreenImage/types.d.ts +18 -0
  66. package/dist/components/SegmentationOverlay/SegmentationOverlay.d.ts +37 -0
  67. package/dist/components/SegmentationOverlay/SegmentationOverlayMaterial.d.ts +31 -0
  68. package/dist/components/SegmentationOverlay/index.d.ts +9 -0
  69. package/dist/components/SegmentationOverlay/maskTexture.d.ts +23 -0
  70. package/dist/components/SegmentationOverlay/providers.d.ts +72 -0
  71. package/dist/components/SegmentationOverlay/settings.d.ts +65 -0
  72. package/dist/components/XRProvider/index.d.ts +16 -2
  73. package/dist/components/XRViewport/hooks/useViewportExternalFaces.d.ts +1 -1
  74. package/dist/components/XRViewport/hooks/useViewportMediaSource.d.ts +1 -1
  75. package/dist/components/XRViewport/hooks/useViewportPipeline.d.ts +1 -1
  76. package/dist/components/index.d.ts +3 -0
  77. package/dist/constants/index.d.ts +4 -1
  78. package/dist/contexts-CO0sd4JQ.cjs +1 -0
  79. package/dist/{contexts-ByhzppYl.js → contexts-FzlnnMYD.js} +252 -246
  80. package/dist/coordinates/feed.d.ts +52 -0
  81. package/dist/coordinates/index.d.ts +5 -0
  82. package/dist/coordinates/spaces.d.ts +49 -0
  83. package/dist/coordinates/viewport.d.ts +22 -0
  84. package/dist/coordinates/world.d.ts +15 -0
  85. package/dist/debug-ui/gesture-settings/index.d.ts +14 -0
  86. package/dist/debug-ui/holistic-tracker-settings/index.d.ts +16 -0
  87. package/dist/debug-ui/index.d.ts +14 -0
  88. package/dist/debug-ui/iris-effect-settings/index.d.ts +12 -0
  89. package/dist/debug-ui/lip-effect-settings/index.d.ts +15 -0
  90. package/dist/debug-ui/media-source.cjs +1 -1
  91. package/dist/debug-ui/media-source.js +1 -1
  92. package/dist/debug-ui/product-hotspots/index.d.ts +24 -0
  93. package/dist/debug-ui/segmentation-overlay-settings/index.d.ts +12 -0
  94. package/dist/debug-ui/xr-diagnostics/index.d.ts +25 -0
  95. package/dist/debug-ui.cjs +3 -3
  96. package/dist/debug-ui.js +2057 -1687
  97. package/dist/detector-K8aej4MB.js +59 -0
  98. package/dist/detector-ijypGtse.cjs +1 -0
  99. package/dist/entries/core.d.ts +18 -1
  100. package/dist/entries/face-effects.d.ts +11 -3
  101. package/dist/entries/low-level.d.ts +22 -3
  102. package/dist/entries/product.d.ts +11 -0
  103. package/dist/entries/tracking.d.ts +24 -1
  104. package/dist/face-effects.cjs +155 -1
  105. package/dist/face-effects.js +1134 -2197
  106. package/dist/gestures/definitions.d.ts +85 -0
  107. package/dist/gestures/detector.d.ts +87 -0
  108. package/dist/gestures/index.d.ts +8 -0
  109. package/dist/gestures/measures.d.ts +101 -0
  110. package/dist/gestures/settings.d.ts +49 -0
  111. package/dist/{getFaceInfo-C4QpCQIY.js → getFaceInfo-BkZfaQs-.js} +5 -5
  112. package/dist/{getFaceInfo-fA1bFBub.cjs → getFaceInfo-ahPxQFGu.cjs} +1 -1
  113. package/dist/hooks/selectors.d.ts +68 -1
  114. package/dist/hooks/useCalibrationFaceTracker.d.ts +1 -1
  115. package/dist/hooks/useFaceInfo.d.ts +13 -1
  116. package/dist/hooks/useFaceInfos.d.ts +1 -1
  117. package/dist/hooks/useGesture.d.ts +32 -0
  118. package/dist/hooks/useIrisTracking.d.ts +45 -0
  119. package/dist/hooks/useXRDiagnostics.d.ts +81 -0
  120. package/dist/hooks/useXRModel.d.ts +7 -0
  121. package/dist/hooks/useXRSession/facade.d.ts +42 -2
  122. package/dist/hooks/useXRSession/index.d.ts +2 -2
  123. package/dist/hooks/useXRSession/reason.d.ts +3 -1
  124. package/dist/hooks/useXRSession/registry.d.ts +14 -0
  125. package/dist/hooks/useXRSession/store.d.ts +52 -3
  126. package/dist/index--RgGzZ6X.cjs +47 -0
  127. package/dist/{index-VJ0SJwmG.js → index-CHVbH0hz.js} +4 -4
  128. package/dist/index-CeVkgsag.cjs +1 -0
  129. package/dist/index-CnGox6Xr.js +3054 -0
  130. package/dist/{index-ByoNj0QP.js → index-CsUdQ-pn.js} +113 -111
  131. package/dist/{index-BjmTe9eM.cjs → index-DKBAh6hV.cjs} +1 -1
  132. package/dist/index-DsZwTfG0.cjs +1 -0
  133. package/dist/index-Dw6tj2Mi.js +144 -0
  134. package/dist/index-OCPjOaeP.cjs +1 -0
  135. package/dist/{index-DXT3WccE.js → index-s9pF4zkG.js} +1065 -1101
  136. package/dist/internal-BYza1h8_.cjs +1 -0
  137. package/dist/{internal-Dmk1cTXq.js → internal-vsfNQycj.js} +15 -16
  138. package/dist/internal.cjs +1 -1
  139. package/dist/internal.js +2 -2
  140. package/dist/iris/compute.d.ts +25 -0
  141. package/dist/iris/index.d.ts +4 -0
  142. package/dist/iris/lead.d.ts +19 -0
  143. package/dist/iris/types.d.ts +87 -0
  144. package/dist/landmarkMask-CbTFzBYG.js +224 -0
  145. package/dist/landmarkMask-u7es2k4X.cjs +1 -0
  146. package/dist/low-level.cjs +1 -1
  147. package/dist/low-level.js +1085 -634
  148. package/dist/main.cjs +1 -1
  149. package/dist/main.js +1519 -465
  150. package/dist/measures-9dQPdw96.js +154 -0
  151. package/dist/measures-KfJzpvod.cjs +1 -0
  152. package/dist/models/Base/index.d.ts +49 -0
  153. package/dist/models/Body/index.d.ts +1 -1
  154. package/dist/models/Face/index.d.ts +1 -1
  155. package/dist/models/Hand/GestureTracking.d.ts +1 -1
  156. package/dist/models/Hand/HandTracking.d.ts +1 -1
  157. package/dist/models/Holistic/index.d.ts +49 -0
  158. package/dist/models/Holistic/result.d.ts +68 -0
  159. package/dist/models/SemanticSegmentation/index.d.ts +31 -0
  160. package/dist/models/SemanticSegmentation/presets.d.ts +28 -0
  161. package/dist/models/index.d.ts +2 -0
  162. package/dist/product/ProductDimensions.d.ts +16 -0
  163. package/dist/product/ProductHotspot.d.ts +16 -0
  164. package/dist/product/ProductViewer.d.ts +9 -0
  165. package/dist/product/details.d.ts +53 -0
  166. package/dist/product/index.d.ts +14 -0
  167. package/dist/product/loadModelViewer.d.ts +4 -0
  168. package/dist/product/types.d.ts +71 -0
  169. package/dist/product/useProductAr.d.ts +37 -0
  170. package/dist/product/useProductDetails.d.ts +60 -0
  171. package/dist/product.cjs +1 -0
  172. package/dist/product.js +414 -0
  173. package/dist/providers-C0Dlhh9Z.js +365 -0
  174. package/dist/providers-YNwkmNeK.cjs +62 -0
  175. package/dist/quality/XRQualityController.d.ts +25 -0
  176. package/dist/quality/controller.d.ts +33 -0
  177. package/dist/quality/index.d.ts +6 -0
  178. package/dist/quality/types.d.ts +100 -0
  179. package/dist/quality/useXRQuality.d.ts +28 -0
  180. package/dist/{renderGroups-KZk6eRiY.js → renderGroups-CN1cGFUo.js} +1 -1
  181. package/dist/{renderGroups-80H3DpTl.cjs → renderGroups-O4KmaMl9.cjs} +1 -1
  182. package/dist/renderPasses-Cg-zqmEz.cjs +21 -0
  183. package/dist/renderPasses-NnKZVfBy.js +1460 -0
  184. package/dist/scene-object.cjs +1 -1
  185. package/dist/scene-object.js +2 -2
  186. package/dist/screenTransform-BenfCtZt.js +44 -0
  187. package/dist/screenTransform-BiXdpVf0.cjs +1 -0
  188. package/dist/segmentation-9PhSvc-R.cjs +1 -0
  189. package/dist/segmentation-CeOTKemr.js +5 -0
  190. package/dist/segmentation2d/faceMemory.d.ts +28 -0
  191. package/dist/segmentation2d/faceRegions.d.ts +24 -0
  192. package/dist/segmentation2d/index.d.ts +9 -0
  193. package/dist/segmentation2d/maskUv.d.ts +23 -0
  194. package/dist/segmentation2d/rasterize.d.ts +14 -0
  195. package/dist/segmentation2d/types.d.ts +46 -0
  196. package/dist/selectors-C5G1PMYL.js +195 -0
  197. package/dist/selectors-Du_PsVnW.cjs +1 -0
  198. package/dist/{session-CpkiK5YA.cjs → session-BBr0yN8h.cjs} +7 -7
  199. package/dist/{session-DLFN_VII.js → session-Cy0m7l7-.js} +76 -76
  200. package/dist/settings-DRR7-snV.cjs +1 -0
  201. package/dist/settings-aQk845NJ.js +73 -0
  202. package/dist/subjects/index.d.ts +2 -0
  203. package/dist/subjects/select.d.ts +62 -0
  204. package/dist/subjects/types.d.ts +55 -0
  205. package/dist/tracking-config/apply.d.ts +57 -0
  206. package/dist/tracking-config/index.d.ts +7 -0
  207. package/dist/tracking-config/resolve.d.ts +25 -0
  208. package/dist/tracking-config/storage.d.ts +8 -0
  209. package/dist/tracking-config/types.d.ts +106 -0
  210. package/dist/tracking-config/useXRTrackingConfig.d.ts +38 -0
  211. package/dist/tracking.cjs +1 -1
  212. package/dist/tracking.js +1056 -383
  213. package/dist/types/compositor.d.ts +21 -0
  214. package/dist/types/holistic.d.ts +121 -0
  215. package/dist/types/index.d.ts +1 -0
  216. package/dist/types/model.d.ts +22 -2
  217. package/dist/types/nodes.d.ts +27 -2
  218. package/dist/types/segmentation.d.ts +19 -0
  219. package/dist/types/session.d.ts +41 -3
  220. package/dist/useFaceInfo-Blf7FCu3.js +303 -0
  221. package/dist/useFaceInfo-C5mO8NQY.cjs +1 -0
  222. package/dist/useXRCapabilities-B1R2ghy-.cjs +1 -0
  223. package/dist/useXRCapabilities-C68v__wB.js +30 -0
  224. package/dist/utils/fns.d.ts +6 -3
  225. package/dist/utils/integrity.d.ts +4 -1
  226. package/dist/utils/updateThrottle.d.ts +2 -0
  227. package/dist/utils/useStableUniforms.d.ts +18 -0
  228. package/docs/api/adaptive-quality.mdx +104 -0
  229. package/docs/api/asset-lifecycle.mdx +78 -0
  230. package/docs/api/camera-permission.mdx +142 -0
  231. package/docs/api/coordinate-spaces.mdx +165 -0
  232. package/docs/api/cross-camera.mdx +88 -0
  233. package/docs/api/diagnostics-calibration.mdx +97 -0
  234. package/docs/api/face-effects.mdx +6 -0
  235. package/docs/api/face-mesh.mdx +4 -2
  236. package/docs/api/gestures.mdx +173 -0
  237. package/docs/api/holistic-tracker.mdx +159 -0
  238. package/docs/api/iris-tracking.mdx +242 -0
  239. package/docs/api/multi-subject.mdx +95 -0
  240. package/docs/api/person-cutout.mdx +136 -0
  241. package/docs/api/product-ar.mdx +111 -0
  242. package/docs/api/product-details.mdx +78 -0
  243. package/docs/api/screen-space-coordinates.mdx +4 -1
  244. package/docs/api/segmentation-overlay.mdx +301 -0
  245. package/docs/api/session-lifecycle.mdx +136 -0
  246. package/docs/api/trackers.mdx +5 -0
  247. package/docs/api/tracking-config.mdx +108 -0
  248. package/docs/docs.json +23 -1
  249. package/docs/examples/lip-shaders.mdx +224 -0
  250. package/docs/guides/lip-effect-textures.mdx +292 -0
  251. package/docs/guides/lip-uv-template.png +0 -0
  252. package/docs/guides/lip-uv-template.svg +1 -0
  253. package/package.json +13 -1
  254. package/dist/FaceMeshRenderer-C5l6VLdO.cjs +0 -155
  255. package/dist/FaceMeshRenderer-wjAHrJzP.js +0 -1270
  256. package/dist/FaceRetouch-BkJzoA79.cjs +0 -134
  257. package/dist/FaceRetouch-DwbKQJAN.js +0 -551
  258. package/dist/contexts-Dr62It_K.cjs +0 -1
  259. package/dist/index-9dlAQAhy.js +0 -1462
  260. package/dist/index-BpEf2BBb.cjs +0 -1
  261. package/dist/index-CyUUurQT.cjs +0 -1
  262. package/dist/index-DCiMbxC3.cjs +0 -1
  263. package/dist/index-DpI-qo5X.cjs +0 -17
  264. package/dist/index-DyVF4vEW.js +0 -111
  265. package/dist/internal-Cq-TEQ5Y.cjs +0 -1
  266. package/dist/renderLayers-lDtL0_43.cjs +0 -1
  267. package/dist/renderLayers-zrK2pv5O.js +0 -13
  268. package/dist/renderPasses-BOoBSr8z.cjs +0 -21
  269. package/dist/renderPasses-BcquyVtu.js +0 -1500
  270. package/dist/selectors-B8H97CKA.js +0 -59
  271. package/dist/selectors-CZLKT2Iv.cjs +0 -1
  272. package/dist/useFaceInfo-BJ8-_MOs.cjs +0 -1
  273. package/dist/useFaceInfo-Dk426LTu.js +0 -62
  274. package/dist/useFaceResults-CtetsO9M.js +0 -19
  275. package/dist/useFaceResults-wBJF3zyp.cjs +0 -1
@@ -0,0 +1,224 @@
1
+ ---
2
+ title: "Lip Shader Examples"
3
+ description: "Custom material factories for LipEffect: animated gloss, noise texture, iridescence, and a time-based shimmer."
4
+ sidebarTitle: "Lip Shaders"
5
+ icon: "wand-magic-sparkles"
6
+ ---
7
+
8
+ {/* Generated by scripts/generate-lip-shader-docs.mjs from example/src/pages/LipEffect/customMaterials.tsx. Edit the source, then re-run. */}
9
+
10
+ `LipEffect`'s `material` prop accepts a factory. It receives a
11
+ `LipEffectMaterialContext` and returns a material node or a three.js material
12
+ instance. These four examples share one component shell and differ only in
13
+ their fragment shader. They are live on the example playground's `/lip-effect`
14
+ page under the material picker; the source is
15
+ `example/src/pages/LipEffect/customMaterials.tsx`.
16
+
17
+ ## What every example relies on
18
+
19
+ - `LIP_EFFECT_VERTEX_SHADER` from `@vincentt-xr/sdk/face-effects` provides
20
+ `vUv` (canonical UV), `vFaceUv` (live camera UV), `vLipEdge` (0 at the outer
21
+ ring, 1 at the mouth line), `vNormal` and `vViewDir`.
22
+ - One `uniforms` object per material, created with `useMemo` and mutated on
23
+ each render. three.js binds the uniforms object when the program compiles,
24
+ so a new object per render would be ignored.
25
+ - `useFrame` advances `uTime` for the animated looks.
26
+ - The stencil test follows `context.maskMode`: `stencilWrite` must be true for
27
+ three.js to run the comparison at all, and the keep-ops stop the material
28
+ from altering the mouth stencil it tests against.
29
+ - Coverage is design alpha × opacity × a feather from `vLipEdge`, read from
30
+ `context.settings`, so the panel controls still apply.
31
+
32
+ ```glsl
33
+ const COMMON_HEAD = `
34
+ uniform sampler2D cameraTexture;
35
+ uniform sampler2D designTexture;
36
+ uniform float useDesign;
37
+ uniform vec3 tint;
38
+ uniform float opacity;
39
+ uniform float edgeSoftness;
40
+ uniform float uTime;
41
+ varying vec2 vFaceUv;
42
+ varying vec2 vUv;
43
+ varying float vLipEdge;
44
+ varying vec3 vNormal;
45
+ varying vec3 vViewDir;
46
+
47
+ float hash(vec2 p) {
48
+ return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);
49
+ }
50
+ float noise(vec2 p) {
51
+ vec2 i = floor(p);
52
+ vec2 f = fract(p);
53
+ f = f * f * (3.0 - 2.0 * f);
54
+ return mix(
55
+ mix(hash(i), hash(i + vec2(1.0, 0.0)), f.x),
56
+ mix(hash(i + vec2(0.0, 1.0)), hash(i + vec2(1.0, 1.0)), f.x),
57
+ f.y
58
+ );
59
+ }
60
+ float coverage() {
61
+ vec4 design = mix(vec4(1.0), texture2D(designTexture, vUv), useDesign);
62
+ float fade = smoothstep(0.0, max(edgeSoftness, 1e-4), vLipEdge);
63
+ return design.a * opacity * fade;
64
+ }
65
+ vec3 facing() {
66
+ vec3 n = normalize(vNormal);
67
+ return gl_FrontFacing ? n : -n;
68
+ }
69
+ `;
70
+ ```
71
+
72
+ ## Animated gloss
73
+
74
+ The key light orbits, sweeping a pulsing highlight across the lips.
75
+
76
+ ````glsl
77
+ void main() {
78
+ vec3 base = texture2D(cameraTexture, vFaceUv).rgb;
79
+ // The key light orbits slowly, so the highlight sweeps across the lips.
80
+ vec3 light = normalize(vec3(sin(uTime * 0.8), 0.6, cos(uTime * 0.8) * 0.5 + 0.8));
81
+ vec3 h = normalize(light + normalize(vViewDir));
82
+ float specular = pow(max(dot(facing(), h), 0.0), 48.0);
83
+ float pulse = 0.75 + 0.25 * sin(uTime * 2.0);
84
+ vec3 painted = tint * (0.6 + 0.8 * dot(base, vec3(0.333)));
85
+ float c = coverage();
86
+ gl_FragColor = vec4(mix(base, painted, c) + specular * pulse * c, c);
87
+ #include <colorspace_fragment>
88
+ }```
89
+
90
+ ## Noise texture
91
+
92
+ Value noise breaks up the paint and a sparse hash adds glitter grains. No image
93
+ texture is needed.
94
+
95
+ ```glsl
96
+ void main() {
97
+ vec3 base = texture2D(cameraTexture, vFaceUv).rgb;
98
+ // Fine value noise breaks up the paint; a sparse hash adds glitter grains.
99
+ float grain = noise(vUv * 420.0);
100
+ float glitter = step(0.985, hash(floor(vUv * 900.0)));
101
+ vec3 painted = tint * (0.75 + 0.5 * grain) + glitter * 0.6;
102
+ painted *= 0.5 + dot(base, vec3(0.333));
103
+ float c = coverage();
104
+ gl_FragColor = vec4(mix(base, painted, c), c);
105
+ #include <colorspace_fragment>
106
+ }```
107
+
108
+ ## Iridescence
109
+
110
+ A cosine palette driven by the viewing angle (fresnel) and the band position,
111
+ drifting slowly over time.
112
+
113
+ ```glsl
114
+ vec3 palette(float t) {
115
+ return 0.5 + 0.5 * cos(6.28318 * (vec3(1.0, 1.0, 1.0) * t + vec3(0.0, 0.33, 0.67)));
116
+ }
117
+ void main() {
118
+ vec3 base = texture2D(cameraTexture, vFaceUv).rgb;
119
+ vec3 n = facing();
120
+ vec3 v = normalize(vViewDir);
121
+ // Hue shifts with the viewing angle (fresnel) and drifts slowly with time.
122
+ float fresnel = pow(1.0 - max(dot(n, v), 0.0), 1.5);
123
+ vec3 sheen = palette(fresnel * 1.2 + vLipEdge * 0.25 + uTime * 0.05);
124
+ vec3 painted = mix(tint, sheen, 0.55 + 0.45 * fresnel) * (0.6 + 0.8 * dot(base, vec3(0.333)));
125
+ vec3 h = normalize(vec3(0.3, 0.6, 1.0) + v);
126
+ float specular = pow(max(dot(n, h), 0.0), 64.0) * 0.8;
127
+ float c = coverage();
128
+ gl_FragColor = vec4(mix(base, painted, c) + specular * c, c);
129
+ #include <colorspace_fragment>
130
+ }```
131
+
132
+ ## Time-based shimmer
133
+
134
+ Per-cell twinkling grains with a slow bright band moving across the lips.
135
+
136
+ ```glsl
137
+ void main() {
138
+ vec3 base = texture2D(cameraTexture, vFaceUv).rgb;
139
+ // Twinkling grains: each cell blinks on its own phase; a bright band sweeps across.
140
+ vec2 cell = floor(vUv * 520.0);
141
+ float seed = hash(cell);
142
+ float twinkle = 0.5 + 0.5 * sin(uTime * 6.0 + seed * 60.0);
143
+ float sparkle = smoothstep(0.96, 1.0, seed * twinkle);
144
+ float band = smoothstep(0.08, 0.0, abs(fract(vUv.x * 2.5 - uTime * 0.25) - 0.5));
145
+ vec3 painted = tint * (0.7 + 0.6 * dot(base, vec3(0.333))) + vec3(sparkle) + band * 0.25;
146
+ float c = coverage();
147
+ gl_FragColor = vec4(mix(base, painted, c), c);
148
+ #include <colorspace_fragment>
149
+ }```
150
+
151
+ ## The factory component
152
+
153
+ ```tsx
154
+ /** One factory component for every example; the shader key picks the look. */
155
+ export const CustomLipShader = ({
156
+ context,
157
+ shader,
158
+ }: {
159
+ context: LipEffectMaterialContext;
160
+ shader: CustomLipShaderKey;
161
+ }) => {
162
+ // One uniforms object for the material's lifetime; values are mutated.
163
+ const uniforms = useMemo(
164
+ () => ({
165
+ cameraTexture: { value: null as THREE.Texture | null },
166
+ designTexture: { value: null as THREE.Texture | null },
167
+ useDesign: { value: 0 },
168
+ tint: { value: new THREE.Color() },
169
+ opacity: { value: 1 },
170
+ edgeSoftness: { value: 0.12 },
171
+ uTime: { value: 0 },
172
+ }),
173
+ [],
174
+ );
175
+ uniforms.cameraTexture.value = context.cameraTexture;
176
+ uniforms.designTexture.value = context.designTexture;
177
+ uniforms.useDesign.value = context.designTexture ? 1 : 0;
178
+ uniforms.tint.value.set(context.settings.color);
179
+ uniforms.opacity.value = context.settings.opacity;
180
+ uniforms.edgeSoftness.value = context.settings.edgeSoftness;
181
+ useFrame((_, delta) => {
182
+ uniforms.uTime.value += delta;
183
+ });
184
+
185
+ return (
186
+ <shaderMaterial
187
+ key={shader}
188
+ uniforms={uniforms}
189
+ vertexShader={LIP_EFFECT_VERTEX_SHADER}
190
+ fragmentShader={SHADERS[shader]}
191
+ transparent
192
+ side={THREE.DoubleSide}
193
+ depthWrite={false}
194
+ toneMapped={false}
195
+ // The stencil test only runs while stencilWrite is true; keep-ops make
196
+ // it a pure comparison against the mouth stencil, writing nothing back.
197
+ stencilWrite
198
+ stencilRef={1}
199
+ stencilFunc={
200
+ context.maskMode === "outer-and-inner-lips"
201
+ ? THREE.NotEqualStencilFunc
202
+ : THREE.AlwaysStencilFunc
203
+ }
204
+ stencilFail={THREE.KeepStencilOp}
205
+ stencilZFail={THREE.KeepStencilOp}
206
+ stencilZPass={THREE.KeepStencilOp}
207
+ />
208
+ );
209
+ };
210
+ ````
211
+
212
+ Use it like any other factory:
213
+
214
+ ```tsx
215
+ <LipEffect
216
+ preset="gloss"
217
+ material={(context) => <CustomLipShader context={context} shader="iridescence" />}
218
+ />
219
+ ```
220
+
221
+ To share one custom material across several faces, build a
222
+ `THREE.ShaderMaterial` yourself, update its uniforms in `useFrame`, and return
223
+ the instance from the factory (or pass it as `sharedMaterial`); the renderer
224
+ sets a material instance on the mesh directly, so several meshes can use it.
@@ -0,0 +1,292 @@
1
+ ---
2
+ title: "Lip Effect Textures"
3
+ description: "How to author a design texture for LipEffect: the canvas contract, the lip UV template, orientation, mask modes, and the custom material context."
4
+ sidebarTitle: "Lip Effect Textures"
5
+ icon: "palette"
6
+ ---
7
+
8
+ `LipEffect` (from `@vincentt-xr/sdk/face-effects`) paints a design texture onto
9
+ the lips of a tracked face. The texture lives in the **canonical face UV
10
+ atlas**, but only the lip triangles are ever sampled. Everything this page
11
+ describes is derived from the canonical mesh's own `uv` attribute: the mesh is
12
+ the design contract, not a hand-drawn diagram.
13
+
14
+ ## The canvas contract
15
+
16
+ - **Square image, any resolution.** 1024×1024 or 2048×2048 is plenty; the lips
17
+ cover a small part of it. The layout is the same atlas as
18
+ `Canonical_Face_Color.png`.
19
+ - **Only the lip region is used.** The outer lip ring spans roughly
20
+ **x 38–62 %** and **y 65–74 %** of the image. Pixels outside the lip
21
+ triangles are never sampled, so leave them transparent or use them for notes.
22
+ - **Transparent means untouched skin.** The alpha channel drives the blend
23
+ (`design.a × opacity`). Soft edges in alpha give soft lip edges.
24
+ - **RGB is tinted by `color`.** At `intensity={1}` the design's RGB is
25
+ multiplied by `color`; at `intensity={0}` the design colours show as painted.
26
+ Paint white or light grey for a pure tint, or paint real colour and lower
27
+ `intensity`.
28
+ - **Image top is `v = 1`.** Textures load with `flipY`, so the top row of the
29
+ image is the top of the UV atlas and the upper lip sits above the lower lip
30
+ in the image, as you would expect.
31
+
32
+ ## The lip UV template
33
+
34
+ <img
35
+ src="/guides/lip-uv-template.svg"
36
+ alt="Lip UV template generated from the canonical face mesh"
37
+ />
38
+
39
+ The template is generated from `canonical_face_model.obj`:
40
+
41
+ - **Solid pink ring** — the outer lip ring (MediaPipe `FACEMESH_LIPS` outer
42
+ contour). This is the painted edge.
43
+ - **Dashed blue ring and blue fill** — the inner lip ring and the mouth
44
+ interior. In the default `outer-and-inner-lips` mask mode this area is cut
45
+ out, so teeth and tongue stay clean when the mouth opens.
46
+ - **Grey wireframe** — the lip triangles that are actually sampled.
47
+ - **Orientation labels** — image **left** is the subject's **right** lip corner.
48
+
49
+ Regenerate it after the canonical OBJ changes on the CDN; the script verifies
50
+ the download against the hash pinned in `lib/utils/integrity.ts`:
51
+
52
+ ```bash
53
+ pnpm dlx tsx scripts/generate-lip-uv-guide.ts --png
54
+ ```
55
+
56
+ ### Mirrored camera behaviour
57
+
58
+ The design is always mapped in the **subject's** frame: the left edge of the
59
+ lip region is the subject's right lip corner, whatever is on screen.
60
+
61
+ - With the **webcam**, the session mirrors the feed once (selfie view), so the
62
+ subject's right appears on **screen right**. The left side of your design
63
+ therefore lands on the right side of the screen.
64
+ - With **image or video sources**, nothing is mirrored, so the subject's right
65
+ (and the left side of your design) appears on **screen left**.
66
+
67
+ Do not add a second mirror in CSS, canvas, or a shader; see "Camera, layout,
68
+ mirror, and capture parity" in `GROUNDING.md`.
69
+
70
+ ### Generating the guide at runtime
71
+
72
+ The same renderer is exported, so an editor or a debug panel can draw the guide
73
+ from the live mesh:
74
+
75
+ ```tsx
76
+ import {
77
+ createLipUvGuideDataUrl,
78
+ createLipUvGuideSvg,
79
+ getLipUvBounds,
80
+ useCanonicalFaceMesh,
81
+ } from "@vincentt-xr/sdk/face-effects";
82
+
83
+ const mesh = useCanonicalFaceMesh();
84
+ const svg = mesh ? createLipUvGuideSvg(mesh, { size: 1024 }) : null;
85
+ const zoomed = mesh ? createLipUvGuideDataUrl(mesh, { region: "lips" }) : null;
86
+ const bounds = mesh ? getLipUvBounds(mesh) : null; // { minU, maxU, minV, maxV }
87
+ ```
88
+
89
+ Options: `size` (canvas pixels), `region` (`"canvas"` or `"lips"`),
90
+ `wireframe`, `labels`, `background`. `lipUvToPixel(u, v, size)` converts a UV
91
+ to image pixels with the `flipY` convention.
92
+
93
+ The example playground's `/lip-effect` page has a **Texture preview / UV
94
+ guide** toggle: it overlays the guide on the current design texture, shows a
95
+ zoomed crop of the lip region, and paints the template itself onto the tracked
96
+ lips so the labelled rings can be checked against a real mouth.
97
+
98
+ ## Presets and material controls
99
+
100
+ `LipEffect` takes flat, serializable settings (`LipEffectSettings`). Start from
101
+ a preset and override what you need; explicit props always win over the preset:
102
+
103
+ ```tsx
104
+ <LipEffect preset="matte" color="#8b2635" designTexture="/lips/matte.png" />
105
+ ```
106
+
107
+ | Preset | Look |
108
+ | ---------- | --------------------------------------------------------------- |
109
+ | `lipstick` | Opaque colour with a soft highlight |
110
+ | `gloss` | Translucent colour with a strong, tight highlight |
111
+ | `matte` | Opaque, no highlight, heavy skin shading |
112
+ | `tint` | Sheer wash of colour that keeps the natural lip |
113
+ | `metallic` | Full-strength, tight gold-tinted highlight |
114
+ | `gradient` | Ombre: strong colour at the mouth line fading at the outer edge |
115
+
116
+ Controls: `color`, `opacity`, `intensity` (0 shows the design as painted, 1
117
+ multiplies it by `color`), `shading` (how much the camera's own lip light and
118
+ shadow show through), `gloss` and `roughness` (highlight amount and spread),
119
+ `highlightColor`, and `gradientColor` with `gradientAmount`. Without a
120
+ `designTexture` the lips are filled with `color`, so every preset works on its
121
+ own.
122
+
123
+ The `LipEffectSettingsPanel` from `@vincentt-xr/sdk/debug-ui` edits all of these
124
+ live, including the mask mode and the texture transform, and the `/lip-effect`
125
+ example page mounts it next to the design-texture picker.
126
+
127
+ ## Procedural colour, edges, inner lip and split lips
128
+
129
+ - **Procedural colour.** Leave `designTexture` out, or set
130
+ `colorMode="solid"` to ignore one, and the lips are filled with `color`.
131
+ Add `gradientColor` with `gradientAmount` and pick `gradientDirection`:
132
+ `outward` runs from the mouth line to the outer edge, `vertical` and
133
+ `horizontal` span the lip box.
134
+ - **Edge softness.** `edgeSoftness` feathers the outer lip boundary as a
135
+ fraction of the lip band (default `0.12`; `0` is a hard polygon edge). It
136
+ uses the mesh's own band position, so it follows the tracked lip shape.
137
+ - **Inner lip.** `innerLipColor` with `innerLipAmount` tints the inner part of
138
+ the lips next to the mouth line; `innerLipWidth` sets how far out it reaches.
139
+ In `outer-lips` mask mode the same tint fills the mouth interior.
140
+ - **Separate lower lip.** Turn on `splitLips` to give the lower lip its own
141
+ `lowerLipColor` and `lowerLipOpacity`, and pass `lowerDesignTexture` for a
142
+ separate texture (it falls back to `designTexture`). The split happens at the
143
+ mouth line of the canonical UV atlas with a thin blend at the corners.
144
+
145
+ ## Texture transform
146
+
147
+ A design that does not line up can be fitted without repainting:
148
+
149
+ | Setting | Effect |
150
+ | ---------------------------------- | --------------------------------------------------------------------------------------------- |
151
+ | `textureScaleX`, `textureScaleY` | Multiplier about the lip centre; `2` makes the design twice as large |
152
+ | `textureOffsetX`, `textureOffsetY` | Fraction of the lip region's width/height; `0.5` moves half a lip width (positive y moves up) |
153
+ | `textureRotation` | Degrees, counter-clockwise as seen on the face |
154
+ | `textureFlipX`, `textureFlipY` | Mirror across the lip centre |
155
+
156
+ The transform is applied to the sampled UV, so the gradient and the mask are
157
+ unaffected. `createLipTextureTransform(settings, bounds)` returns the same
158
+ `Matrix3` the shader uses if a custom material wants it.
159
+
160
+ ## Downloading the template
161
+
162
+ The `/lip-effect` page has **Download SVG** and **Download PNG** buttons that
163
+ export the guide at 2048 px straight from the loaded mesh. In code,
164
+ `createLipUvGuideSvg(mesh, { size })` returns the SVG string and
165
+ `createLipUvGuidePngBlob(mesh, { size })` resolves to a PNG `Blob` (browser
166
+ only). The shipped copies are `docs/guides/lip-uv-template.svg` and
167
+ `docs/guides/lip-uv-template.png`.
168
+
169
+ ## Mask modes
170
+
171
+ ```tsx
172
+ <LipEffect designTexture="/lips/gloss.png" maskMode="outer-and-inner-lips" />
173
+ ```
174
+
175
+ - `outer-and-inner-lips` (default) — paint the lip surface only. The mouth
176
+ interior writes the shared stencil buffer and the lip material skips it.
177
+ - `outer-lips` — paint everything inside the outer ring, mouth interior
178
+ included.
179
+
180
+ ## Several faces and performance
181
+
182
+ `LipEffects` renders one lip effect per face slot. Pass one config for every
183
+ face or a picker per face:
184
+
185
+ ```tsx
186
+ <LipEffects maxFaces={2} faces={{ preset: "gloss", designTexture: "/lips/gloss.png" }} />
187
+ <LipEffects
188
+ maxFaces={2}
189
+ faces={(faceIndex) =>
190
+ faceIndex === 0 ? { preset: "matte", color: "#8b2635" } : { preset: "gloss" }
191
+ }
192
+ />
193
+ ```
194
+
195
+ With a single config the faces share one built-in material. The material is a
196
+ plain three.js object underneath: `useLipEffectMaterial(inputs)` returns one you
197
+ can pass as `sharedMaterial` to any number of `LipEffect`s, or return from a
198
+ `material` factory. `maxUpdateFps` caps how often the lip mesh follows the
199
+ landmarks, and `<XRProvider perf={{ targetFps, camRes }}>` lowers the tracking
200
+ rate and the analysed camera resolution for the whole session.
201
+
202
+ ## Custom materials
203
+
204
+ `material` accepts a React material node or a factory. The factory receives a
205
+ stable context and is called once per lip geometry group (plus the mouth
206
+ interior in `outer-lips` mode), only after the canonical mesh has loaded:
207
+
208
+ ```ts
209
+ type LipEffectMaterialContext = {
210
+ cameraTexture: THREE.Texture | null;
211
+ designTexture: THREE.Texture | null;
212
+ faceUv: THREE.BufferAttribute;
213
+ lipEdge: THREE.BufferAttribute;
214
+ lowerDesignTexture: THREE.Texture | null;
215
+ faceIndex: number;
216
+ maskMode: LipMaskMode;
217
+ lipUvBounds: LipUvBounds;
218
+ settings: LipEffectSettings;
219
+ };
220
+ ```
221
+
222
+ `lipEdge` is a static per-vertex position across the lip band: `0` on the
223
+ outer ring, `1` on the mouth line. It is bound as `attribute float lipEdge`
224
+ and is what the built-in material uses for feathering, the outward gradient
225
+ and the inner-lip tint. `lipUvBounds.mouthV` is the mouth line in UV space.
226
+
227
+ `faceUv` is the live per-vertex camera-texture UV. It is already bound to the
228
+ geometry, so a custom vertex shader reads it as `attribute vec2 faceUv`; the
229
+ attribute object is exposed for uniforms, debugging, or readback.
230
+
231
+ ```tsx
232
+ <LipEffect
233
+ designTexture={texture}
234
+ material={({ cameraTexture, designTexture, maskMode }) => (
235
+ <shaderMaterial
236
+ uniforms={{
237
+ cameraTexture: { value: cameraTexture },
238
+ designTexture: { value: designTexture },
239
+ }}
240
+ vertexShader={`
241
+ attribute vec2 faceUv;
242
+ varying vec2 vFaceUv; varying vec2 vUv;
243
+ void main() {
244
+ vUv = uv; vFaceUv = faceUv;
245
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
246
+ }`}
247
+ fragmentShader={`
248
+ uniform sampler2D cameraTexture; uniform sampler2D designTexture;
249
+ varying vec2 vFaceUv; varying vec2 vUv;
250
+ void main() {
251
+ vec4 design = texture2D(designTexture, vUv);
252
+ vec3 skin = texture2D(cameraTexture, vFaceUv).rgb;
253
+ gl_FragColor = vec4(skin * design.rgb, design.a);
254
+ }`}
255
+ transparent
256
+ depthWrite={false}
257
+ stencilWrite
258
+ stencilRef={1}
259
+ stencilFunc={
260
+ maskMode === "outer-and-inner-lips" ? THREE.NotEqualStencilFunc : THREE.AlwaysStencilFunc
261
+ }
262
+ stencilFail={THREE.KeepStencilOp}
263
+ stencilZFail={THREE.KeepStencilOp}
264
+ stencilZPass={THREE.KeepStencilOp}
265
+ />
266
+ )}
267
+ />
268
+ ```
269
+
270
+ Four complete factories (animated gloss, noise texture, iridescence, time-based
271
+ shimmer) are documented in [Lip Shader Examples](/examples/lip-shaders) and run
272
+ on the `/lip-effect` page.
273
+
274
+ Honour `maskMode` with the stencil test shown above; that is exactly what the
275
+ built-in `LipEffectMaterial` does through its `subtractMouth` prop. Note that
276
+ three.js only evaluates `stencilFunc` while `stencilWrite` is true, so keep it
277
+ on and use the keep-ops: the material then compares against the mouth stencil
278
+ without ever writing to it. The lip triangles already exclude the mouth cavity,
279
+ so the stencil is the guard for anything that reaches past them. It is
280
+ exported so you can reuse the default shader with different settings:
281
+
282
+ ```tsx
283
+ material={(context) => (
284
+ <LipEffectMaterial
285
+ cameraTexture={context.cameraTexture}
286
+ designTexture={context.designTexture}
287
+ settings={resolveLipEffectSettings({ ...context.settings, preset: "metallic" })}
288
+ lipUvBounds={context.lipUvBounds}
289
+ subtractMouth={context.maskMode === "outer-and-inner-lips"}
290
+ />
291
+ )}
292
+ ```
Binary file
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="1024" height="1024" viewBox="0 0 1024 1024"><rect x="1.28" y="1.28" width="1021.44" height="1021.44" fill="none" stroke="#cbd5e1" stroke-width="2.56"/><path d="M540.93,666.01L511.98,668.19L539.77,682.19ZM483.07,666.01L484.23,682.19L511.98,668.19ZM512.02,682.22L539.77,682.19L511.98,668.19ZM512.02,682.22L511.98,668.19L484.23,682.19ZM540.93,666.01L539.77,682.19L573.66,673ZM483.07,666.01L450.34,673L484.23,682.19ZM566.45,684.57L573.66,673L539.77,682.19ZM457.55,684.57L484.23,682.19L450.34,673ZM573.66,673L566.45,684.57L599.43,682.54ZM450.34,673L424.57,682.54L457.55,684.57ZM591.09,690.06L599.43,682.54L566.45,684.57ZM432.91,690.06L457.55,684.57L424.57,682.54ZM591.09,690.06L613.64,697.41L599.43,682.54ZM432.91,690.06L424.57,682.54L410.36,697.41ZM622.18,693.97L599.43,682.54L613.64,697.41ZM401.82,693.97L410.36,697.41L424.57,682.54ZM584.94,699.08L582.49,708.98L607.44,702.13ZM439.06,699.08L416.55,702.13L441.51,708.98ZM600.69,708.98L607.44,702.13L582.49,708.98ZM423.31,708.98L441.51,708.98L416.55,702.13ZM611.29,723.5L618.39,727.26L626.58,710.62ZM412.71,723.5L397.42,710.62L405.61,727.26ZM632.86,711.38L626.58,710.62L618.39,727.26ZM391.14,711.38L405.61,727.26L397.42,710.62ZM590.68,728.93L595.65,737.34L611.29,723.5ZM433.32,728.93L412.71,723.5L428.35,737.34ZM618.39,727.26L611.29,723.5L595.65,737.34ZM405.61,727.26L428.35,737.34L412.71,723.5ZM568.49,748.33L595.65,737.34L566.16,732.99ZM455.51,748.33L457.84,732.99L428.35,737.34ZM590.68,728.93L566.16,732.99L595.65,737.34ZM433.32,728.93L428.35,737.34L457.84,732.99ZM511.98,754.71L540.34,753.9L511.98,736.65ZM511.98,754.71L511.98,736.65L483.66,753.9ZM539.56,735.09L511.98,736.65L540.34,753.9ZM484.44,735.09L483.66,753.9L511.98,736.65ZM604.54,718.67L622.17,710.86L600.88,712.09ZM419.46,718.67L423.12,712.09L401.81,710.86ZM610.68,710.61L600.88,712.09L622.17,710.86ZM413.32,710.61L401.81,710.86L423.12,712.09ZM626.58,710.62L622.17,710.86L611.29,723.5ZM397.42,710.62L412.71,723.5L401.81,710.86ZM604.54,718.67L611.29,723.5L622.17,710.86ZM419.46,718.67L401.81,710.86L412.71,723.5ZM539.77,682.19L538.47,696.52L566.45,684.57ZM484.23,682.19L457.55,684.57L485.53,696.52ZM562.82,697.2L566.45,684.57L538.47,696.52ZM461.18,697.2L485.53,696.52L457.55,684.57ZM566.45,684.57L562.82,697.2L591.09,690.06ZM457.55,684.57L432.91,690.06L461.18,697.2ZM584.94,699.08L591.09,690.06L562.82,697.2ZM439.06,699.08L461.18,697.2L432.91,690.06ZM591.09,690.06L584.94,699.08L613.64,697.41ZM432.91,690.06L410.36,697.41L439.06,699.08ZM607.44,702.13L613.64,697.41L584.94,699.08ZM416.55,702.13L439.06,699.08L410.36,697.41ZM587.29,720.42L590.68,728.93L604.54,718.67ZM436.71,720.42L419.46,718.67L433.32,728.93ZM611.29,723.5L604.54,718.67L590.68,728.93ZM412.71,723.5L433.32,728.93L419.46,718.67ZM566.16,732.99L590.68,728.93L565.23,721.54ZM457.84,732.99L458.77,721.54L433.32,728.93ZM587.29,720.42L565.23,721.54L590.68,728.93ZM436.71,720.42L433.32,728.93L458.77,721.54ZM511.98,736.65L539.56,735.09L511.98,722.88ZM511.98,736.65L511.98,722.88L484.44,735.09ZM539.52,721.54L511.98,722.88L539.56,735.09ZM484.48,721.54L484.44,735.09L511.98,722.88ZM511.98,722.88L539.52,721.54L511.98,711.96ZM511.98,722.88L511.98,711.96L484.48,721.54ZM539.61,711.96L511.98,711.96L539.52,721.54ZM484.39,711.96L484.48,721.54L511.98,711.96ZM564.57,711.96L565.23,721.54L585.79,711.96ZM459.43,711.96L438.21,711.96L458.77,721.54ZM587.29,720.42L585.79,711.96L565.23,721.54ZM436.71,720.42L458.77,721.54L438.21,711.96ZM600.88,712.09L585.79,711.96L604.54,718.67ZM423.12,712.09L419.46,718.67L438.21,711.96ZM587.29,720.42L604.54,718.67L585.79,711.96ZM436.71,720.42L438.21,711.96L419.46,718.67ZM562.82,697.2L560.97,708.98L584.94,699.08ZM461.18,697.2L439.06,699.08L463.03,708.98ZM582.49,708.98L584.94,699.08L560.97,708.98ZM441.51,708.98L463.03,708.98L439.06,699.08ZM538.47,696.52L537.2,708.98L562.82,697.2ZM485.53,696.52L461.18,697.2L486.8,708.98ZM560.97,708.98L562.82,697.2L537.2,708.98ZM463.03,708.98L486.8,708.98L461.18,697.2ZM607.44,702.13L600.69,708.98L622.17,710.86ZM416.55,702.13L401.81,710.86L423.31,708.98ZM610.68,710.61L622.17,710.86L600.69,708.98ZM413.32,710.61L423.31,708.98L401.81,710.86ZM512.02,682.22L512.02,695.53L539.77,682.19ZM512.02,682.22L484.23,682.19L512.02,695.53ZM538.47,696.52L539.77,682.19L512.02,695.53ZM485.53,696.52L512.02,695.53L484.23,682.19ZM512.02,695.53L512.02,708.96L538.47,696.52ZM512.02,695.53L485.53,696.52L512.02,708.96ZM537.2,708.98L538.47,696.52L512.02,708.96ZM486.8,708.98L512.02,708.96L485.53,696.52ZM539.52,721.54L565.23,721.54L539.61,711.96ZM484.48,721.54L484.39,711.96L458.77,721.54ZM564.57,711.96L539.61,711.96L565.23,721.54ZM459.43,711.96L458.77,721.54L484.39,711.96ZM539.56,735.09L566.16,732.99L539.52,721.54ZM484.44,735.09L484.48,721.54L457.84,732.99ZM565.23,721.54L539.52,721.54L566.16,732.99ZM458.77,721.54L457.84,732.99L484.48,721.54ZM540.34,753.9L568.49,748.33L539.56,735.09ZM483.66,753.9L484.44,735.09L455.51,748.33ZM566.16,732.99L539.56,735.09L568.49,748.33ZM457.84,732.99L455.51,748.33L484.44,735.09ZM613.64,697.41L607.44,702.13L626.58,710.62ZM410.36,697.41L397.42,710.62L416.55,702.13ZM622.17,710.86L626.58,710.62L607.44,702.13ZM401.81,710.86L416.55,702.13L397.42,710.62ZM613.64,697.41L626.58,710.62L622.18,693.97ZM410.36,697.41L401.82,693.97L397.42,710.62ZM632.86,711.38L622.18,693.97L626.58,710.62ZM391.14,711.38L397.42,710.62L401.82,693.97Z" fill="#e85d75" fill-opacity="0.08" stroke="#94a3b8" stroke-width="1.28" stroke-linejoin="round"/><path d="M610.68,710.61L600.69,708.98L600.88,712.09ZM413.32,710.61L423.12,712.09L423.31,708.98ZM511.98,711.96L539.61,711.96L512.02,708.96ZM511.98,711.96L512.02,708.96L484.39,711.96ZM537.2,708.98L512.02,708.96L539.61,711.96ZM486.8,708.98L484.39,711.96L512.02,708.96ZM539.61,711.96L564.57,711.96L537.2,708.98ZM484.39,711.96L486.8,708.98L459.43,711.96ZM560.97,708.98L537.2,708.98L564.57,711.96ZM463.03,708.98L459.43,711.96L486.8,708.98ZM564.57,711.96L585.79,711.96L560.97,708.98ZM459.43,711.96L463.03,708.98L438.21,711.96ZM582.49,708.98L560.97,708.98L585.79,711.96ZM441.51,708.98L438.21,711.96L463.03,708.98ZM585.79,711.96L600.88,712.09L582.49,708.98ZM438.21,711.96L441.51,708.98L423.12,712.09ZM600.69,708.98L582.49,708.98L600.88,712.09ZM423.31,708.98L423.12,712.09L441.51,708.98Z" fill="#2563eb" fill-opacity="0.25" stroke="none"/><polygon points="391.14,711.38 405.61,727.26 428.35,737.34 455.51,748.33 483.66,753.9 511.98,754.71 540.34,753.9 568.49,748.33 595.65,737.34 618.39,727.26 632.86,711.38 622.18,693.97 599.43,682.54 573.66,673 540.93,666.01 511.98,668.19 483.07,666.01 450.34,673 424.57,682.54 401.82,693.97" fill="none" stroke="#e85d75" stroke-width="2.56" stroke-linejoin="round"/><polygon points="413.32,710.61 423.12,712.09 438.21,711.96 459.43,711.96 484.39,711.96 511.98,711.96 539.61,711.96 564.57,711.96 585.79,711.96 600.88,712.09 610.68,710.61 600.69,708.98 582.49,708.98 560.97,708.98 537.2,708.98 512.02,708.96 486.8,708.98 463.03,708.98 441.51,708.98 423.31,708.98" fill="none" stroke="#2563eb" stroke-width="2.56" stroke-dasharray="7.68 5.12" stroke-linejoin="round"/><text x="378.85" y="710.36" text-anchor="end" font-family="ui-monospace, SFMono-Regular, Menlo, monospace" font-size="16.38" fill="#0f172a">subject's RIGHT ▸</text><text x="645.15" y="710.36" text-anchor="start" font-family="ui-monospace, SFMono-Regular, Menlo, monospace" font-size="16.38" fill="#0f172a">◂ subject's LEFT</text><text x="512" y="653.73" text-anchor="middle" font-family="ui-monospace, SFMono-Regular, Menlo, monospace" font-size="16.38" fill="#0f172a">upper lip (outer ring = painted edge)</text><text x="512" y="783.38" text-anchor="middle" font-family="ui-monospace, SFMono-Regular, Menlo, monospace" font-size="16.38" fill="#0f172a">lower lip · dashed ring = mouth interior, hidden in outer-and-inner-lips mode</text><text x="512" y="804.68" text-anchor="middle" font-family="ui-monospace, SFMono-Regular, Menlo, monospace" font-size="16.38" fill="#0f172a">lip region: u 0.38–0.62, v 0.26–0.35 (image x 38–62%, y 65–74%)</text><text x="25.6" y="41.98" text-anchor="start" font-family="ui-monospace, SFMono-Regular, Menlo, monospace" font-size="16.38" fill="#0f172a" font-weight="bold">Lip UV template — canonical face UV atlas</text><text x="25.6" y="63.28" text-anchor="start" font-family="ui-monospace, SFMono-Regular, Menlo, monospace" font-size="16.38" fill="#0f172a">1024×1024 canvas, same layout as Canonical_Face_Color.png.</text><text x="25.6" y="84.58" text-anchor="start" font-family="ui-monospace, SFMono-Regular, Menlo, monospace" font-size="16.38" fill="#0f172a">Only the lip triangles are sampled; transparent pixels leave the skin untouched.</text><text x="25.6" y="105.88" text-anchor="start" font-family="ui-monospace, SFMono-Regular, Menlo, monospace" font-size="16.38" fill="#0f172a">Image LEFT = subject's RIGHT (screen-right on a mirrored webcam view).</text><text x="25.6" y="998.4" text-anchor="start" font-family="ui-monospace, SFMono-Regular, Menlo, monospace" font-size="16.38" fill="#0f172a">generated from canonical_face_model.obj uv attributes</text></svg>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vincentt-xr/sdk",
3
- "version": "2.0.0-alpha.7",
3
+ "version": "2.0.0-alpha.8",
4
4
  "description": "XR SDK by Vincentt",
5
5
  "repository": {
6
6
  "type": "git",
@@ -63,6 +63,11 @@
63
63
  "import": "./dist/internal.js",
64
64
  "require": "./dist/internal.cjs"
65
65
  },
66
+ "./product": {
67
+ "types": "./dist/entries/product.d.ts",
68
+ "import": "./dist/product.js",
69
+ "require": "./dist/product.cjs"
70
+ },
66
71
  "./debug-ui": {
67
72
  "types": "./dist/debug-ui/index.d.ts",
68
73
  "import": "./dist/debug-ui.js",
@@ -80,6 +85,7 @@
80
85
  }
81
86
  },
82
87
  "peerDependencies": {
88
+ "@google/model-viewer": "^4.0.0",
83
89
  "@mediapipe/tasks-vision": "^0.10.18",
84
90
  "@react-three/drei": "9.105.6",
85
91
  "@react-three/fiber": "8.18.0",
@@ -89,6 +95,9 @@
89
95
  "three": "0.173.0"
90
96
  },
91
97
  "peerDependenciesMeta": {
98
+ "@google/model-viewer": {
99
+ "optional": true
100
+ },
92
101
  "@mediapipe/tasks-vision": {
93
102
  "optional": false
94
103
  },
@@ -98,7 +107,9 @@
98
107
  },
99
108
  "devDependencies": {
100
109
  "@eslint/js": "^9.14.0",
110
+ "@google/model-viewer": "4.0.0",
101
111
  "@mdx-js/rollup": "^3.1.1",
112
+ "@playwright/test": "1.47.2",
102
113
  "@testing-library/dom": "^10",
103
114
  "@testing-library/react": "^16",
104
115
  "@types/node": "^22.9.0",
@@ -156,6 +167,7 @@
156
167
  "format:check": "prettier --check 'lib/**/*.{ts,tsx}' 'example/**/*.{ts,tsx}' '*.{json,md,mjs,ts}' '.github/**/*.{md,yml}' 'docs/**/*.{md,mdx,json}'",
157
168
  "format": "prettier --write 'lib/**/*.{js,jsx,ts,tsx}' 'example/**/*.{js,jsx,ts,tsx}'",
158
169
  "test": "vitest run",
170
+ "smoke": "playwright test",
159
171
  "test:watch": "vitest",
160
172
  "lint:check": "eslint lib --max-warnings 0",
161
173
  "example:build": "vite build --config example/vite.config.ts",