@visutry/tryon-core 0.2.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 (86) hide show
  1. package/README.md +58 -0
  2. package/dist/__fixtures__/faceFixtures.d.ts +13 -0
  3. package/dist/__fixtures__/faceFixtures.d.ts.map +1 -0
  4. package/dist/__fixtures__/faceFixtures.js +206 -0
  5. package/dist/__fixtures__/faceFixtures.js.map +1 -0
  6. package/dist/adapter/visutry-site.d.ts +76 -0
  7. package/dist/adapter/visutry-site.d.ts.map +1 -0
  8. package/dist/adapter/visutry-site.js +172 -0
  9. package/dist/adapter/visutry-site.js.map +1 -0
  10. package/dist/analytics.d.ts +89 -0
  11. package/dist/analytics.d.ts.map +1 -0
  12. package/dist/analytics.js +49 -0
  13. package/dist/analytics.js.map +1 -0
  14. package/dist/coordinate/CoordinateSystem.d.ts +46 -0
  15. package/dist/coordinate/CoordinateSystem.d.ts.map +1 -0
  16. package/dist/coordinate/CoordinateSystem.js +88 -0
  17. package/dist/coordinate/CoordinateSystem.js.map +1 -0
  18. package/dist/face/FaceMetricsCalculator.d.ts +52 -0
  19. package/dist/face/FaceMetricsCalculator.d.ts.map +1 -0
  20. package/dist/face/FaceMetricsCalculator.js +375 -0
  21. package/dist/face/FaceMetricsCalculator.js.map +1 -0
  22. package/dist/face/FaceSemanticMapper.d.ts +54 -0
  23. package/dist/face/FaceSemanticMapper.d.ts.map +1 -0
  24. package/dist/face/FaceSemanticMapper.js +129 -0
  25. package/dist/face/FaceSemanticMapper.js.map +1 -0
  26. package/dist/face/FaceShapeScorer.d.ts +35 -0
  27. package/dist/face/FaceShapeScorer.d.ts.map +1 -0
  28. package/dist/face/FaceShapeScorer.js +265 -0
  29. package/dist/face/FaceShapeScorer.js.map +1 -0
  30. package/dist/face/feature-extractor.d.ts +46 -0
  31. package/dist/face/feature-extractor.d.ts.map +1 -0
  32. package/dist/face/feature-extractor.js +106 -0
  33. package/dist/face/feature-extractor.js.map +1 -0
  34. package/dist/face/logreg-classifier.d.ts +117 -0
  35. package/dist/face/logreg-classifier.d.ts.map +1 -0
  36. package/dist/face/logreg-classifier.js +304 -0
  37. package/dist/face/logreg-classifier.js.map +1 -0
  38. package/dist/feature-flag.d.ts +43 -0
  39. package/dist/feature-flag.d.ts.map +1 -0
  40. package/dist/feature-flag.js +58 -0
  41. package/dist/feature-flag.js.map +1 -0
  42. package/dist/i18n/index.d.ts +15 -0
  43. package/dist/i18n/index.d.ts.map +1 -0
  44. package/dist/i18n/index.js +91 -0
  45. package/dist/i18n/index.js.map +1 -0
  46. package/dist/index.d.ts +24 -0
  47. package/dist/index.d.ts.map +1 -0
  48. package/dist/index.js +33 -0
  49. package/dist/index.js.map +1 -0
  50. package/dist/manifest/ManifestValidator.d.ts +23 -0
  51. package/dist/manifest/ManifestValidator.d.ts.map +1 -0
  52. package/dist/manifest/ManifestValidator.js +129 -0
  53. package/dist/manifest/ManifestValidator.js.map +1 -0
  54. package/dist/pose/GlassesPoseSolver.d.ts +64 -0
  55. package/dist/pose/GlassesPoseSolver.d.ts.map +1 -0
  56. package/dist/pose/GlassesPoseSolver.js +299 -0
  57. package/dist/pose/GlassesPoseSolver.js.map +1 -0
  58. package/dist/privacy/PrivacyGuard.d.ts +44 -0
  59. package/dist/privacy/PrivacyGuard.d.ts.map +1 -0
  60. package/dist/privacy/PrivacyGuard.js +105 -0
  61. package/dist/privacy/PrivacyGuard.js.map +1 -0
  62. package/dist/quality/QualityGate.d.ts +22 -0
  63. package/dist/quality/QualityGate.d.ts.map +1 -0
  64. package/dist/quality/QualityGate.js +161 -0
  65. package/dist/quality/QualityGate.js.map +1 -0
  66. package/dist/smoothing/PoseSmoothing.d.ts +37 -0
  67. package/dist/smoothing/PoseSmoothing.d.ts.map +1 -0
  68. package/dist/smoothing/PoseSmoothing.js +146 -0
  69. package/dist/smoothing/PoseSmoothing.js.map +1 -0
  70. package/dist/types/index.d.ts +444 -0
  71. package/dist/types/index.d.ts.map +1 -0
  72. package/dist/types/index.js +8 -0
  73. package/dist/types/index.js.map +1 -0
  74. package/dist/utils/errors.d.ts +7 -0
  75. package/dist/utils/errors.d.ts.map +1 -0
  76. package/dist/utils/errors.js +20 -0
  77. package/dist/utils/errors.js.map +1 -0
  78. package/dist/utils/index.d.ts +2 -0
  79. package/dist/utils/index.d.ts.map +1 -0
  80. package/dist/utils/index.js +2 -0
  81. package/dist/utils/index.js.map +1 -0
  82. package/dist/utils/math.d.ts +40 -0
  83. package/dist/utils/math.d.ts.map +1 -0
  84. package/dist/utils/math.js +149 -0
  85. package/dist/utils/math.js.map +1 -0
  86. package/package.json +31 -0
@@ -0,0 +1,91 @@
1
+ /**
2
+ * VisuTry SDK — lightweight i18n for user-facing error messages.
3
+ *
4
+ * The SDK keeps all hard-coded user-facing strings behind the `t()` lookup so
5
+ * that platform adapters (web / wechat) and host applications can localise the
6
+ * error messages surfaced to end users. The message catalogue is intentionally
7
+ * small: it only covers the canonical SDK error strings emitted via
8
+ * `createSDKError`. Callers can switch the active locale at runtime with
9
+ * `setLocale()`; unknown keys fall back to English, then to the key itself.
10
+ */
11
+ const messages = {
12
+ "en": {
13
+ "error.camera_not_initialized": "Camera is not initialized.",
14
+ "error.camera_permission_denied": "Camera permission denied.",
15
+ "error.camera_not_available": "No suitable camera device found.",
16
+ "error.camera_unsupported": "getUserMedia is not available on this platform.",
17
+ "error.tracker_init_failed": "Failed to initialize face tracker.",
18
+ "error.tracker_not_initialized": "Face tracker is not initialized.",
19
+ "error.tracker_detect_failed": "Face detection failed.",
20
+ "error.renderer_init_failed": "Failed to initialize renderer.",
21
+ "error.glasses_load_failed": "Failed to load glasses model.",
22
+ "error.snapshot_failed": "Snapshot capture failed.",
23
+ "error.snapshot_disabled": "Snapshot export is disabled by privacy policy.",
24
+ "error.analysis_timeout": "Face analysis timed out waiting for quality frames.",
25
+ "error.analysis_in_progress": "Face shape analysis already in progress.",
26
+ "error.sdk_destroyed": "SDK has been destroyed.",
27
+ "error.renderer_disposed": "Renderer has been disposed.",
28
+ },
29
+ "zh-CN": {
30
+ "error.camera_not_initialized": "摄像头未初始化。",
31
+ "error.camera_permission_denied": "摄像头权限被拒绝。",
32
+ "error.camera_not_available": "未找到合适的摄像头设备。",
33
+ "error.camera_unsupported": "当前平台不支持摄像头功能。",
34
+ "error.tracker_init_failed": "人脸追踪器初始化失败。",
35
+ "error.tracker_not_initialized": "人脸追踪器未初始化。",
36
+ "error.tracker_detect_failed": "人脸检测失败。",
37
+ "error.renderer_init_failed": "渲染器初始化失败。",
38
+ "error.glasses_load_failed": "眼镜模型加载失败。",
39
+ "error.snapshot_failed": "截图失败。",
40
+ "error.snapshot_disabled": "隐私策略已禁用截图导出。",
41
+ "error.analysis_timeout": "脸型分析超时,未获取到足够的高质量帧。",
42
+ "error.analysis_in_progress": "脸型分析正在进行中。",
43
+ "error.sdk_destroyed": "SDK 已被销毁。",
44
+ "error.renderer_disposed": "渲染器已被销毁。",
45
+ },
46
+ "ja": {
47
+ "error.camera_not_initialized": "カメラが初期化されていません。",
48
+ "error.camera_permission_denied": "カメラの権限が拒否されました。",
49
+ "error.camera_not_available": "適切なカメラデバイスが見つかりません。",
50
+ "error.camera_unsupported": "このプラットフォームではカメラ機能を使用できません。",
51
+ "error.tracker_init_failed": "顔トラッカーの初期化に失敗しました。",
52
+ "error.tracker_not_initialized": "顔トラッカーが初期化されていません。",
53
+ "error.tracker_detect_failed": "顔検出に失敗しました。",
54
+ "error.renderer_init_failed": "レンダラーの初期化に失敗しました。",
55
+ "error.glasses_load_failed": "眼鏡モデルの読み込みに失敗しました。",
56
+ "error.snapshot_failed": "スクリーンショットの取得に失敗しました。",
57
+ "error.snapshot_disabled": "プライバシーポリシーによりスクリーンショットエクスポートが無効です。",
58
+ "error.analysis_timeout": "顔分析がタイムアウトしました。",
59
+ "error.analysis_in_progress": "顔分析は既に進行中です。",
60
+ "error.sdk_destroyed": "SDKは破棄されました。",
61
+ "error.renderer_disposed": "レンダラーは破棄されました。",
62
+ },
63
+ "ko": {
64
+ "error.camera_not_initialized": "카메라가 초기화되지 않았습니다.",
65
+ "error.camera_permission_denied": "카메라 권한이 거부되었습니다.",
66
+ "error.camera_not_available": "적합한 카메라 장치를 찾을 수 없습니다.",
67
+ "error.camera_unsupported": "이 플랫폼에서는 카메라 기능을 사용할 수 없습니다.",
68
+ "error.tracker_init_failed": "얼굴 트래커 초기화에 실패했습니다.",
69
+ "error.tracker_not_initialized": "얼굴 트래커가 초기화되지 않았습니다.",
70
+ "error.tracker_detect_failed": "얼굴 감지에 실패했습니다.",
71
+ "error.renderer_init_failed": "렌더러 초기화에 실패했습니다.",
72
+ "error.glasses_load_failed": "안경 모델 로드에 실패했습니다.",
73
+ "error.snapshot_failed": "스냅샷 캡처에 실패했습니다.",
74
+ "error.snapshot_disabled": "개인정보 보호 정책으로 인해 스냅샷 내보내기가 비활성화되었습니다.",
75
+ "error.analysis_timeout": "얼굴 분석 시간이 초과되었습니다.",
76
+ "error.analysis_in_progress": "얼굴 분석이 이미 진행 중입니다.",
77
+ "error.sdk_destroyed": "SDK가 폐기되었습니다.",
78
+ "error.renderer_disposed": "렌더러가 폐기되었습니다.",
79
+ },
80
+ };
81
+ let currentLocale = "en";
82
+ export function setLocale(locale) {
83
+ currentLocale = locale;
84
+ }
85
+ export function getLocale() {
86
+ return currentLocale;
87
+ }
88
+ export function t(key) {
89
+ return messages[currentLocale]?.[key] ?? messages["en"][key] ?? key;
90
+ }
91
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/i18n/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,MAAM,QAAQ,GAA2C;IACvD,IAAI,EAAE;QACJ,8BAA8B,EAAE,4BAA4B;QAC5D,gCAAgC,EAAE,2BAA2B;QAC7D,4BAA4B,EAAE,kCAAkC;QAChE,0BAA0B,EAAE,iDAAiD;QAC7E,2BAA2B,EAAE,oCAAoC;QACjE,+BAA+B,EAAE,kCAAkC;QACnE,6BAA6B,EAAE,wBAAwB;QACvD,4BAA4B,EAAE,gCAAgC;QAC9D,2BAA2B,EAAE,+BAA+B;QAC5D,uBAAuB,EAAE,0BAA0B;QACnD,yBAAyB,EAAE,gDAAgD;QAC3E,wBAAwB,EAAE,qDAAqD;QAC/E,4BAA4B,EAAE,0CAA0C;QACxE,qBAAqB,EAAE,yBAAyB;QAChD,yBAAyB,EAAE,6BAA6B;KACzD;IACD,OAAO,EAAE;QACP,8BAA8B,EAAE,UAAU;QAC1C,gCAAgC,EAAE,WAAW;QAC7C,4BAA4B,EAAE,cAAc;QAC5C,0BAA0B,EAAE,eAAe;QAC3C,2BAA2B,EAAE,aAAa;QAC1C,+BAA+B,EAAE,YAAY;QAC7C,6BAA6B,EAAE,SAAS;QACxC,4BAA4B,EAAE,WAAW;QACzC,2BAA2B,EAAE,WAAW;QACxC,uBAAuB,EAAE,OAAO;QAChC,yBAAyB,EAAE,cAAc;QACzC,wBAAwB,EAAE,qBAAqB;QAC/C,4BAA4B,EAAE,YAAY;QAC1C,qBAAqB,EAAE,WAAW;QAClC,yBAAyB,EAAE,UAAU;KACtC;IACD,IAAI,EAAE;QACJ,8BAA8B,EAAE,iBAAiB;QACjD,gCAAgC,EAAE,iBAAiB;QACnD,4BAA4B,EAAE,qBAAqB;QACnD,0BAA0B,EAAE,4BAA4B;QACxD,2BAA2B,EAAE,oBAAoB;QACjD,+BAA+B,EAAE,oBAAoB;QACrD,6BAA6B,EAAE,aAAa;QAC5C,4BAA4B,EAAE,mBAAmB;QACjD,2BAA2B,EAAE,oBAAoB;QACjD,uBAAuB,EAAE,sBAAsB;QAC/C,yBAAyB,EAAE,oCAAoC;QAC/D,wBAAwB,EAAE,iBAAiB;QAC3C,4BAA4B,EAAE,cAAc;QAC5C,qBAAqB,EAAE,cAAc;QACrC,yBAAyB,EAAE,gBAAgB;KAC5C;IACD,IAAI,EAAE;QACJ,8BAA8B,EAAE,mBAAmB;QACnD,gCAAgC,EAAE,kBAAkB;QACpD,4BAA4B,EAAE,wBAAwB;QACtD,0BAA0B,EAAE,8BAA8B;QAC1D,2BAA2B,EAAE,qBAAqB;QAClD,+BAA+B,EAAE,sBAAsB;QACvD,6BAA6B,EAAE,gBAAgB;QAC/C,4BAA4B,EAAE,kBAAkB;QAChD,2BAA2B,EAAE,mBAAmB;QAChD,uBAAuB,EAAE,iBAAiB;QAC1C,yBAAyB,EAAE,sCAAsC;QACjE,wBAAwB,EAAE,oBAAoB;QAC9C,4BAA4B,EAAE,oBAAoB;QAClD,qBAAqB,EAAE,eAAe;QACtC,yBAAyB,EAAE,eAAe;KAC3C;CACF,CAAC;AAEF,IAAI,aAAa,GAAW,IAAI,CAAC;AAEjC,MAAM,UAAU,SAAS,CAAC,MAAc;IACtC,aAAa,GAAG,MAAM,CAAC;AACzB,CAAC;AAED,MAAM,UAAU,SAAS;IACvB,OAAO,aAAa,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,CAAC,CAAC,GAAW;IAC3B,OAAO,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC;AACtE,CAAC"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * @visutry/tryon-core
3
+ *
4
+ * Platform-agnostic core of the VisuTry Face Geometry & AR Glasses Try-On SDK.
5
+ * No DOM, MediaPipe, Three.js or WeChat dependencies live here.
6
+ */
7
+ export * from "./types/index.js";
8
+ export { setLocale, getLocale, t } from "./i18n/index.js";
9
+ export type { Locale } from "./i18n/index.js";
10
+ export { CoordinateSystem } from "./coordinate/CoordinateSystem.js";
11
+ export { FaceSemanticMapper, MEDIAPIPE_SEMANTIC_INDEX_MAP, } from "./face/FaceSemanticMapper.js";
12
+ export type { SemanticIndexMap, FaceSemanticMapperOptions } from "./face/FaceSemanticMapper.js";
13
+ export { FaceMetricsCalculator } from "./face/FaceMetricsCalculator.js";
14
+ export { FaceShapeScorer, FACE_SHAPE_SCORER_VERSION } from "./face/FaceShapeScorer.js";
15
+ export { GlassesPoseSolver, DEFAULT_FITTING_CONFIG, MM_TO_RENDER_WORLD, decomposeMatrixToEuler, degreesToRadians, } from "./pose/GlassesPoseSolver.js";
16
+ export { PoseSmoother, DEFAULT_POSE_SMOOTHING_CONFIG, } from "./smoothing/PoseSmoothing.js";
17
+ export { QualityGate } from "./quality/QualityGate.js";
18
+ export { PrivacyGuard, DEFAULT_PRIVACY_CONFIG } from "./privacy/PrivacyGuard.js";
19
+ export { ManifestValidator, } from "./manifest/ManifestValidator.js";
20
+ export type { ManifestValidationIssue, ManifestValidationResult, } from "./manifest/ManifestValidator.js";
21
+ export { createSDKError } from "./utils/errors.js";
22
+ export * as math from "./utils/math.js";
23
+ export { clamp, clamp01, clampAngle, lerp, lerpVec3, distance2D, distance3D, mean, median, trimmedMean, standardDeviation, softmax, minMaxNormalize, mapRange, DEG2RAD, RAD2DEG, } from "./utils/math.js";
24
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,cAAc,kBAAkB,CAAC;AAGjC,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,iBAAiB,CAAC;AAC1D,YAAY,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAG9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AAGpE,OAAO,EACL,kBAAkB,EAClB,4BAA4B,GAC7B,MAAM,8BAA8B,CAAC;AACtC,YAAY,EAAE,gBAAgB,EAAE,yBAAyB,EAAE,MAAM,8BAA8B,CAAC;AAGhG,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AAGxE,OAAO,EAAE,eAAe,EAAE,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;AAGvF,OAAO,EACL,iBAAiB,EACjB,sBAAsB,EACtB,kBAAkB,EAClB,sBAAsB,EACtB,gBAAgB,GACjB,MAAM,6BAA6B,CAAC;AAGrC,OAAO,EACL,YAAY,EACZ,6BAA6B,GAC9B,MAAM,8BAA8B,CAAC;AAGtC,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAGvD,OAAO,EAAE,YAAY,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AAGjF,OAAO,EACL,iBAAiB,GAClB,MAAM,iCAAiC,CAAC;AACzC,YAAY,EACV,uBAAuB,EACvB,wBAAwB,GACzB,MAAM,iCAAiC,CAAC;AAGzC,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,KAAK,IAAI,MAAM,iBAAiB,CAAC;AACxC,OAAO,EACL,KAAK,EACL,OAAO,EACP,UAAU,EACV,IAAI,EACJ,QAAQ,EACR,UAAU,EACV,UAAU,EACV,IAAI,EACJ,MAAM,EACN,WAAW,EACX,iBAAiB,EACjB,OAAO,EACP,eAAe,EACf,QAAQ,EACR,OAAO,EACP,OAAO,GACR,MAAM,iBAAiB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,33 @@
1
+ /**
2
+ * @visutry/tryon-core
3
+ *
4
+ * Platform-agnostic core of the VisuTry Face Geometry & AR Glasses Try-On SDK.
5
+ * No DOM, MediaPipe, Three.js or WeChat dependencies live here.
6
+ */
7
+ // Types
8
+ export * from "./types/index.js";
9
+ // i18n (user-facing error message localisation)
10
+ export { setLocale, getLocale, t } from "./i18n/index.js";
11
+ // Coordinate system
12
+ export { CoordinateSystem } from "./coordinate/CoordinateSystem.js";
13
+ // Face semantic mapping
14
+ export { FaceSemanticMapper, MEDIAPIPE_SEMANTIC_INDEX_MAP, } from "./face/FaceSemanticMapper.js";
15
+ // Face metrics
16
+ export { FaceMetricsCalculator } from "./face/FaceMetricsCalculator.js";
17
+ // Face shape scoring
18
+ export { FaceShapeScorer, FACE_SHAPE_SCORER_VERSION } from "./face/FaceShapeScorer.js";
19
+ // Glasses pose solver
20
+ export { GlassesPoseSolver, DEFAULT_FITTING_CONFIG, MM_TO_RENDER_WORLD, decomposeMatrixToEuler, degreesToRadians, } from "./pose/GlassesPoseSolver.js";
21
+ // Pose smoothing
22
+ export { PoseSmoother, DEFAULT_POSE_SMOOTHING_CONFIG, } from "./smoothing/PoseSmoothing.js";
23
+ // Quality gate
24
+ export { QualityGate } from "./quality/QualityGate.js";
25
+ // Privacy
26
+ export { PrivacyGuard, DEFAULT_PRIVACY_CONFIG } from "./privacy/PrivacyGuard.js";
27
+ // Manifest validation
28
+ export { ManifestValidator, } from "./manifest/ManifestValidator.js";
29
+ // Utilities
30
+ export { createSDKError } from "./utils/errors.js";
31
+ export * as math from "./utils/math.js";
32
+ export { clamp, clamp01, clampAngle, lerp, lerpVec3, distance2D, distance3D, mean, median, trimmedMean, standardDeviation, softmax, minMaxNormalize, mapRange, DEG2RAD, RAD2DEG, } from "./utils/math.js";
33
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,QAAQ;AACR,cAAc,kBAAkB,CAAC;AAEjC,gDAAgD;AAChD,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,iBAAiB,CAAC;AAG1D,oBAAoB;AACpB,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AAEpE,wBAAwB;AACxB,OAAO,EACL,kBAAkB,EAClB,4BAA4B,GAC7B,MAAM,8BAA8B,CAAC;AAGtC,eAAe;AACf,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AAExE,qBAAqB;AACrB,OAAO,EAAE,eAAe,EAAE,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;AAEvF,sBAAsB;AACtB,OAAO,EACL,iBAAiB,EACjB,sBAAsB,EACtB,kBAAkB,EAClB,sBAAsB,EACtB,gBAAgB,GACjB,MAAM,6BAA6B,CAAC;AAErC,iBAAiB;AACjB,OAAO,EACL,YAAY,EACZ,6BAA6B,GAC9B,MAAM,8BAA8B,CAAC;AAEtC,eAAe;AACf,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEvD,UAAU;AACV,OAAO,EAAE,YAAY,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AAEjF,sBAAsB;AACtB,OAAO,EACL,iBAAiB,GAClB,MAAM,iCAAiC,CAAC;AAMzC,YAAY;AACZ,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,KAAK,IAAI,MAAM,iBAAiB,CAAC;AACxC,OAAO,EACL,KAAK,EACL,OAAO,EACP,UAAU,EACV,IAAI,EACJ,QAAQ,EACR,UAAU,EACV,UAAU,EACV,IAAI,EACJ,MAAM,EACN,WAAW,EACX,iBAAiB,EACjB,OAAO,EACP,eAAe,EACf,QAAQ,EACR,OAAO,EACP,OAAO,GACR,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,23 @@
1
+ import type { GlassesAssetManifest } from "../types/index.js";
2
+ export interface ManifestValidationIssue {
3
+ field: string;
4
+ message: string;
5
+ severity: "error" | "warning";
6
+ }
7
+ export interface ManifestValidationResult {
8
+ valid: boolean;
9
+ issues: ManifestValidationIssue[];
10
+ }
11
+ /**
12
+ * Validates a `GlassesAssetManifest` against the SDK model standard (spec §14).
13
+ *
14
+ * The validator is used at glasses-load time to fail fast on malformed assets,
15
+ * and by the eval tooling to keep the official demo models compliant.
16
+ */
17
+ export declare class ManifestValidator {
18
+ validate(manifest: unknown): ManifestValidationResult;
19
+ /** Throw if invalid — convenience for load-time enforcement. */
20
+ validateOrThrow(manifest: unknown): asserts manifest is GlassesAssetManifest;
21
+ private isVector3;
22
+ }
23
+ //# sourceMappingURL=ManifestValidator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ManifestValidator.d.ts","sourceRoot":"","sources":["../../src/manifest/ManifestValidator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAE9D,MAAM,WAAW,uBAAuB;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAC;CAC/B;AAED,MAAM,WAAW,wBAAwB;IACvC,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,uBAAuB,EAAE,CAAC;CACnC;AAED;;;;;GAKG;AACH,qBAAa,iBAAiB;IAC5B,QAAQ,CAAC,QAAQ,EAAE,OAAO,GAAG,wBAAwB;IAgHrD,gEAAgE;IAChE,eAAe,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,IAAI,oBAAoB;IAU5E,OAAO,CAAC,SAAS;CASlB"}
@@ -0,0 +1,129 @@
1
+ /**
2
+ * Validates a `GlassesAssetManifest` against the SDK model standard (spec §14).
3
+ *
4
+ * The validator is used at glasses-load time to fail fast on malformed assets,
5
+ * and by the eval tooling to keep the official demo models compliant.
6
+ */
7
+ export class ManifestValidator {
8
+ validate(manifest) {
9
+ const issues = [];
10
+ // --- Structural type guard -------------------------------------------------
11
+ if (manifest === null || typeof manifest !== "object") {
12
+ return {
13
+ valid: false,
14
+ issues: [{ field: "(root)", message: "manifest must be a non-null object", severity: "error" }],
15
+ };
16
+ }
17
+ const m = manifest;
18
+ // --- Top-level identity ----------------------------------------------
19
+ if (typeof m.id !== "string" || m.id.length === 0) {
20
+ issues.push({ field: "id", message: "id must be a non-empty string", severity: "error" });
21
+ }
22
+ if (typeof m.name !== "string" || m.name.length === 0) {
23
+ issues.push({ field: "name", message: "name must be a non-empty string", severity: "error" });
24
+ }
25
+ if (typeof m.modelUrl !== "string" || m.modelUrl.length === 0) {
26
+ issues.push({ field: "modelUrl", message: "modelUrl must be a non-empty string", severity: "error" });
27
+ }
28
+ if (typeof m.format !== "string" || (m.format !== "glb" && m.format !== "gltf")) {
29
+ issues.push({ field: "format", message: "format must be 'glb' or 'gltf'", severity: "error" });
30
+ }
31
+ // --- Coordinate system ------------------------------------------------
32
+ const cs = m.coordinateSystem;
33
+ if (!cs || typeof cs !== "object") {
34
+ issues.push({ field: "coordinateSystem", message: "coordinateSystem is required and must be an object", severity: "error" });
35
+ }
36
+ else {
37
+ if (!["millimeter", "centimeter", "meter"].includes(cs.unit ?? "")) {
38
+ issues.push({ field: "coordinateSystem.unit", message: "unit must be millimeter|centimeter|meter", severity: "error" });
39
+ }
40
+ if (cs.forwardAxis !== "+z" && cs.forwardAxis !== "-z") {
41
+ issues.push({ field: "coordinateSystem.forwardAxis", message: "forwardAxis must be '+z' or '-z'", severity: "error" });
42
+ }
43
+ if (cs.upAxis !== "+y" && cs.upAxis !== "+z") {
44
+ issues.push({ field: "coordinateSystem.upAxis", message: "upAxis must be '+y' or '+z'", severity: "error" });
45
+ }
46
+ }
47
+ // --- Dimensions -------------------------------------------------------
48
+ const dims = m.dimensions;
49
+ if (!dims) {
50
+ issues.push({ field: "dimensions", message: "dimensions is required", severity: "error" });
51
+ }
52
+ else {
53
+ if (typeof dims.frameWidthMm !== "number" || dims.frameWidthMm <= 0) {
54
+ issues.push({ field: "dimensions.frameWidthMm", message: "frameWidthMm must be a positive number", severity: "error" });
55
+ }
56
+ else if (dims.frameWidthMm < 80 || dims.frameWidthMm > 200) {
57
+ issues.push({
58
+ field: "dimensions.frameWidthMm",
59
+ message: "frameWidthMm outside typical range 80–200mm — verify model units",
60
+ severity: "warning",
61
+ });
62
+ }
63
+ if (dims.lensWidthMm !== undefined && (dims.lensWidthMm <= 0 || dims.lensWidthMm > 80)) {
64
+ issues.push({ field: "dimensions.lensWidthMm", message: "lensWidthMm should be in (0, 80]", severity: "warning" });
65
+ }
66
+ }
67
+ // --- Anchors ----------------------------------------------------------
68
+ const anchors = m.anchors;
69
+ if (!anchors) {
70
+ issues.push({ field: "anchors", message: "anchors is required", severity: "error" });
71
+ }
72
+ else {
73
+ if (!this.isVector3(anchors.origin)) {
74
+ issues.push({ field: "anchors.origin", message: "origin must be a Vector3", severity: "error" });
75
+ }
76
+ if (!this.isVector3(anchors.noseBridge)) {
77
+ issues.push({ field: "anchors.noseBridge", message: "noseBridge must be a Vector3", severity: "error" });
78
+ }
79
+ }
80
+ // --- Fitting ----------------------------------------------------------
81
+ const fitting = m.fitting;
82
+ if (!fitting) {
83
+ issues.push({ field: "fitting", message: "fitting is required", severity: "error" });
84
+ }
85
+ else {
86
+ if (typeof fitting.defaultScale !== "number" || fitting.defaultScale <= 0) {
87
+ issues.push({ field: "fitting.defaultScale", message: "defaultScale must be a positive number", severity: "error" });
88
+ }
89
+ if (!this.isVector3(fitting.defaultOffset)) {
90
+ issues.push({ field: "fitting.defaultOffset", message: "defaultOffset must be a Vector3", severity: "error" });
91
+ }
92
+ if (!this.isVector3(fitting.defaultRotation)) {
93
+ issues.push({ field: "fitting.defaultRotation", message: "defaultRotation must be a Vector3", severity: "error" });
94
+ }
95
+ if (fitting.minScale !== undefined &&
96
+ fitting.maxScale !== undefined &&
97
+ fitting.minScale > fitting.maxScale) {
98
+ issues.push({ field: "fitting.minScale", message: "minScale must be <= maxScale", severity: "error" });
99
+ }
100
+ }
101
+ // --- Material (optional but type-checked) ----------------------------
102
+ if (m.material) {
103
+ if (m.material.lensOpacity !== undefined && (m.material.lensOpacity < 0 || m.material.lensOpacity > 1)) {
104
+ issues.push({ field: "material.lensOpacity", message: "lensOpacity must be in [0,1]", severity: "error" });
105
+ }
106
+ if (m.material.frameRoughness !== undefined && (m.material.frameRoughness < 0 || m.material.frameRoughness > 1)) {
107
+ issues.push({ field: "material.frameRoughness", message: "frameRoughness must be in [0,1]", severity: "error" });
108
+ }
109
+ }
110
+ const valid = issues.filter((i) => i.severity === "error").length === 0;
111
+ return { valid, issues };
112
+ }
113
+ /** Throw if invalid — convenience for load-time enforcement. */
114
+ validateOrThrow(manifest) {
115
+ const result = this.validate(manifest);
116
+ if (!result.valid) {
117
+ const errors = result.issues.filter((i) => i.severity === "error");
118
+ throw new Error(`Invalid glasses manifest: ${errors.map((e) => `${e.field} (${e.message})`).join("; ")}`);
119
+ }
120
+ }
121
+ isVector3(v) {
122
+ return (!!v &&
123
+ typeof v === "object" &&
124
+ typeof v.x === "number" &&
125
+ typeof v.y === "number" &&
126
+ typeof v.z === "number");
127
+ }
128
+ }
129
+ //# sourceMappingURL=ManifestValidator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ManifestValidator.js","sourceRoot":"","sources":["../../src/manifest/ManifestValidator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,64 @@
1
+ import type { GlassesFittingConfig, GlassesPose, GlassesPoseSolverInput } from "../types/index.js";
2
+ /**
3
+ * Calibration constant: maps millimetres to render-world units.
4
+ *
5
+ * The render-world is defined so that the full frame height maps to 1.0 unit and
6
+ * the x-axis is scaled by aspect ratio. We assume a representative adult face
7
+ * height of ~200 mm, hence 1 mm ≈ 0.005 render-world units. This is a documented
8
+ * calibration anchor; the manifest `defaultScale` and `GlassesFittingConfig`
9
+ * fine-tune per model.
10
+ */
11
+ export declare const MM_TO_RENDER_WORLD: number;
12
+ /** Default fitting configuration. */
13
+ export declare const DEFAULT_FITTING_CONFIG: GlassesFittingConfig;
14
+ /**
15
+ * Converts a normalized `NormalizedFaceResult` into a `GlassesPose` that the
16
+ * renderer can apply directly to a glasses model.
17
+ *
18
+ * Coordinate contract:
19
+ * - Face landmarks arrive in *normalized-image* space (origin top-left, y down).
20
+ * - The solver converts them to *render-world* space (origin centre, y up,
21
+ * x scaled by aspect ratio, 1.0 unit = frame height) before computing.
22
+ * - The renderer must use the same render-world convention so that
23
+ * `GlassesPose.position` lands the model on the face.
24
+ *
25
+ * Solve pipeline (spec §15.5):
26
+ * 1. eye centre line → roll
27
+ * 2. outer-eye distance → scale
28
+ * 3. noseBridge / eyeLine → position
29
+ * 4. yaw / pitch (or matrix) → 3D rotation
30
+ * 5. manifest defaults + config offsets applied
31
+ */
32
+ export declare class GlassesPoseSolver {
33
+ /**
34
+ * Solve the glasses pose for a single face result.
35
+ */
36
+ solve(input: GlassesPoseSolverInput): GlassesPose;
37
+ private computeRoll;
38
+ private computeScale;
39
+ /**
40
+ * The face-side width in render-world units used to fit the glasses. The model
41
+ * frame width should match the outer-eye span, so we use that directly.
42
+ */
43
+ private fitMetricRW;
44
+ private modelFrameWidthMm;
45
+ private computePosition;
46
+ private computeRotation;
47
+ private applyPositionOffsets;
48
+ private applyRotationOffsets;
49
+ private clampScale;
50
+ private assessVisibility;
51
+ private deriveAspect;
52
+ }
53
+ /**
54
+ * Decompose a column-major 4x4 rigid transformation matrix into Euler angles
55
+ * (radians) in YXZ order. Used when `useTransformationMatrix` is enabled.
56
+ */
57
+ export declare function decomposeMatrixToEuler(matrix: number[]): {
58
+ x: number;
59
+ y: number;
60
+ z: number;
61
+ };
62
+ /** Convert degrees to radians for manifest authors who think in degrees. */
63
+ export declare function degreesToRadians(deg: number): number;
64
+ //# sourceMappingURL=GlassesPoseSolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GlassesPoseSolver.d.ts","sourceRoot":"","sources":["../../src/pose/GlassesPoseSolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,oBAAoB,EACpB,WAAW,EACX,sBAAsB,EAIvB,MAAM,mBAAmB,CAAC;AAI3B;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,QAAU,CAAC;AAE1C,qCAAqC;AACrC,eAAO,MAAM,sBAAsB,EAAE,oBAQpC,CAAC;AAEF;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,iBAAiB;IAC5B;;OAEG;IACH,KAAK,CAAC,KAAK,EAAE,sBAAsB,GAAG,WAAW;IAkDjD,OAAO,CAAC,WAAW;IAkBnB,OAAO,CAAC,YAAY;IAoBpB;;;OAGG;IACH,OAAO,CAAC,WAAW;IA+BnB,OAAO,CAAC,iBAAiB;IAczB,OAAO,CAAC,eAAe;IAkDvB,OAAO,CAAC,eAAe;IAiBvB,OAAO,CAAC,oBAAoB;IAc5B,OAAO,CAAC,oBAAoB;IAc5B,OAAO,CAAC,UAAU;IAelB,OAAO,CAAC,gBAAgB;IA4BxB,OAAO,CAAC,YAAY;CAUrB;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CA2B5F;AAED,4EAA4E;AAC5E,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEpD"}