@neofaceid/web-sdk 1.17.0 → 1.19.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.
@@ -3428,7 +3428,16 @@ const CALIBRATION = {
3428
3428
  YAW_LEFT_THRESHOLD: 15,
3429
3429
  YAW_RIGHT_THRESHOLD: -15,
3430
3430
  CAPTURE_HOLD_TIME: 1500,
3431
- DETECTION_INTERVAL: 200
3431
+ DETECTION_INTERVAL: 150,
3432
+ // Um pouco mais rápido para melhor resposta
3433
+ MIN_FACE_WIDTH: 160,
3434
+ // Rosto deve ocupar boa parte do oval (era ~120 implícito)
3435
+ MAX_FACE_WIDTH: 280,
3436
+ // Evita rosto "colado" na câmera
3437
+ CENTER_X_THRESHOLD: 0.15,
3438
+ // Rosto deve estar centralizado (desvio max 15%)
3439
+ CENTER_Y_THRESHOLD: 0.2
3440
+ // Rosto deve estar centralizado verticalmente
3432
3441
  };
3433
3442
  function BiometricRegistrationModal({
3434
3443
  personData,
@@ -3450,7 +3459,8 @@ function BiometricRegistrationModal({
3450
3459
  const captureStateRef = useRef(null);
3451
3460
  const [state, dispatch] = useReducer(modalReducer, initialState);
3452
3461
  const [faceDetected, setFaceDetected] = useState(false);
3453
- const [_faceDistance, setFaceDistance] = useState("ok");
3462
+ const [faceDistance, setFaceDistance] = useState("ok");
3463
+ const [cameraReady, setCameraReady] = useState(false);
3454
3464
  useEffect(() => {
3455
3465
  if (state.status === "liveness") {
3456
3466
  const newStep = state.step;
@@ -3512,6 +3522,18 @@ function BiometricRegistrationModal({
3512
3522
  return null;
3513
3523
  }
3514
3524
  };
3525
+ const checkFacePosition = (box, videoWidth, videoHeight) => {
3526
+ if (box.width < CALIBRATION.MIN_FACE_WIDTH) return "too-far";
3527
+ if (box.width > CALIBRATION.MAX_FACE_WIDTH) return "too-close";
3528
+ const faceCenterX = box.x + box.width / 2;
3529
+ const faceCenterY = box.y + box.height / 2;
3530
+ const deviationX = Math.abs(faceCenterX - videoWidth / 2) / videoWidth;
3531
+ const deviationY = Math.abs(faceCenterY - videoHeight / 2) / videoHeight;
3532
+ if (deviationX > CALIBRATION.CENTER_X_THRESHOLD || deviationY > CALIBRATION.CENTER_Y_THRESHOLD) {
3533
+ return "not-centered";
3534
+ }
3535
+ return "ok";
3536
+ };
3515
3537
  const checkPositionMatch = (pitch, yaw, step) => {
3516
3538
  switch (step) {
3517
3539
  case "center":
@@ -3652,7 +3674,11 @@ function BiometricRegistrationModal({
3652
3674
  }
3653
3675
  video.srcObject = stream;
3654
3676
  streamRef.current = stream;
3655
- await video.play();
3677
+ video.onloadedmetadata = () => {
3678
+ video.play().then(() => {
3679
+ if (mounted) setCameraReady(true);
3680
+ });
3681
+ };
3656
3682
  } catch (error) {
3657
3683
  if (!mounted) return;
3658
3684
  if (watchdogTimerRef.current) {
@@ -3722,14 +3748,17 @@ function BiometricRegistrationModal({
3722
3748
  const hasFace = !!detection;
3723
3749
  setFaceDetected(hasFace);
3724
3750
  if (hasFace && detection.detection) {
3725
- const box = detection.detection.box;
3726
- const faceWidth = box.width;
3727
- if (faceWidth > 250) {
3728
- setFaceDistance("too-close");
3729
- } else if (faceWidth < 120) {
3730
- setFaceDistance("too-far");
3731
- } else {
3732
- setFaceDistance("ok");
3751
+ const video2 = videoRef.current;
3752
+ const positionStatus = checkFacePosition(
3753
+ detection.detection.box,
3754
+ video2.videoWidth,
3755
+ video2.videoHeight
3756
+ );
3757
+ setFaceDistance(positionStatus);
3758
+ if (positionStatus !== "ok") {
3759
+ manageHoldAndCapture(false);
3760
+ requestAnimationFrame(detectFace2);
3761
+ return;
3733
3762
  }
3734
3763
  }
3735
3764
  if (hasFace && detection.landmarks) {
@@ -3911,12 +3940,26 @@ function BiometricRegistrationModal({
3911
3940
  const stepProgress = state.stepProgress;
3912
3941
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "liveness-container", children: [
3913
3942
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "progress-indicator", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "progress-text", children: progress }) }),
3943
+ faceDetected && faceDistance !== "ok" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `face-badge ${faceDistance === "not-centered" ? "warning" : "error"}`, children: [
3944
+ faceDistance === "too-far" && "Aproxime-se mais",
3945
+ faceDistance === "too-close" && "Rosto muito perto",
3946
+ faceDistance === "not-centered" && "Centralize seu rosto"
3947
+ ] }),
3914
3948
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "video-wrapper", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
3915
3949
  "div",
3916
3950
  {
3917
3951
  className: `video-circle ${faceDetected ? "face-detected" : ""} ${stepProgress > 0 ? "capturing" : ""}`,
3918
3952
  children: [
3919
- /* @__PURE__ */ jsxRuntimeExports.jsx("video", { ref: videoRef, className: "video-feed", autoPlay: true, muted: true, playsInline: true }),
3953
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
3954
+ "video",
3955
+ {
3956
+ ref: videoRef,
3957
+ className: `video-feed ${cameraReady ? "ready" : ""}`,
3958
+ autoPlay: true,
3959
+ muted: true,
3960
+ playsInline: true
3961
+ }
3962
+ ),
3920
3963
  faceDetected && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "face-badge", children: [
3921
3964
  /* @__PURE__ */ jsxRuntimeExports.jsx("svg", { width: "16", height: "16", viewBox: "0 0 20 20", fill: "none", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
3922
3965
  "path",
@@ -4387,8 +4430,9 @@ function BiometricRegistrationModal({
4387
4430
  border-radius: 50%;
4388
4431
  overflow: hidden;
4389
4432
  position: relative;
4390
- transition: all 0.3s ease;
4433
+ /* Removida transição 'all' para evitar salto de zoom no início */
4391
4434
  box-shadow: 0 0 0 4px rgba(124, 58, 237, 0.3);
4435
+ background: #000;
4392
4436
  }
4393
4437
 
4394
4438
  .video-circle.face-detected {
@@ -4405,6 +4449,12 @@ function BiometricRegistrationModal({
4405
4449
  height: 100%;
4406
4450
  object-fit: cover;
4407
4451
  transform: scaleX(-1);
4452
+ opacity: 0;
4453
+ transition: opacity 0.4s ease;
4454
+ }
4455
+
4456
+ .video-feed.ready {
4457
+ opacity: 1;
4408
4458
  }
4409
4459
 
4410
4460
  .face-badge {
@@ -6835,7 +6885,7 @@ const biometricDetection = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.
6835
6885
  initializeBiometricDetection,
6836
6886
  isAdvancedDetectionAvailable
6837
6887
  }, Symbol.toStringTag, { value: "Module" }));
6838
- const VERSION = "1.17.0";
6888
+ const VERSION = "1.19.0";
6839
6889
  const RELEASE_DATE = "2026-03-13";
6840
6890
  class OnboardingCaptureModal {
6841
6891
  constructor(options) {