@jupitermetalabs/face-zk-sdk 0.3.2 → 0.3.3

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.
@@ -0,0 +1,451 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta
6
+ name="viewport"
7
+ content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
8
+ />
9
+ <title>Identity Verification</title>
10
+
11
+ <!-- Console Bridge for React Native Debugging -->
12
+ <script>
13
+ (function () {
14
+ var orig = {
15
+ log: console.log,
16
+ warn: console.warn,
17
+ error: console.error,
18
+ };
19
+ function bridge(level, args) {
20
+ orig[level].apply(console, args);
21
+ if (window.ReactNativeWebView) {
22
+ try {
23
+ window.ReactNativeWebView.postMessage(
24
+ JSON.stringify({
25
+ type: "log",
26
+ level: level,
27
+ message: Array.from(args).map(String).join(" "),
28
+ }),
29
+ );
30
+ } catch (e) {}
31
+ }
32
+ }
33
+ console.log = function () {
34
+ bridge("log", arguments);
35
+ };
36
+ console.warn = function () {
37
+ bridge("warn", arguments);
38
+ };
39
+ console.error = function () {
40
+ bridge("error", arguments);
41
+ };
42
+ })();
43
+ </script>
44
+
45
+ <!-- Minimal Inline CSS to replace Tailwind CDN -->
46
+ <style>
47
+ /* Reset & Base */
48
+ * {
49
+ box-sizing: border-box;
50
+ margin: 0;
51
+ padding: 0;
52
+ }
53
+ body {
54
+ background-color: #f8fafc;
55
+ min-height: 100vh;
56
+ display: flex;
57
+ align-items: center;
58
+ justify-content: center;
59
+ font-family:
60
+ ui-sans-serif,
61
+ system-ui,
62
+ -apple-system,
63
+ BlinkMacSystemFont,
64
+ "Segoe UI",
65
+ Roboto,
66
+ "Helvetica Neue",
67
+ Arial,
68
+ sans-serif;
69
+ }
70
+ .tw-container {
71
+ max-width: 28rem;
72
+ width: 100%;
73
+ background-color: #ffffff;
74
+ border-radius: 1.5rem;
75
+ box-shadow:
76
+ 0 20px 25px -5px rgba(0, 0, 0, 0.1),
77
+ 0 10px 10px -5px rgba(0, 0, 0, 0.04);
78
+ padding: 2rem;
79
+ text-align: center;
80
+ position: relative;
81
+ overflow: hidden;
82
+ }
83
+ .tw-title {
84
+ font-size: 1.5rem;
85
+ line-height: 2rem;
86
+ font-weight: 700;
87
+ color: #1e293b;
88
+ margin-bottom: 0.5rem;
89
+ }
90
+ .tw-subtitle {
91
+ color: #64748b;
92
+ margin-bottom: 2rem;
93
+ min-height: 24px;
94
+ }
95
+ .tw-hidden {
96
+ display: none !important;
97
+ }
98
+ .tw-opacity-0 {
99
+ opacity: 0;
100
+ }
101
+ .tw-transition {
102
+ transition-property: opacity;
103
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
104
+ transition-duration: 300ms;
105
+ }
106
+ .tw-text-xs {
107
+ font-size: 0.75rem;
108
+ line-height: 1rem;
109
+ }
110
+ .tw-text-slate-400 {
111
+ color: #94a3b8;
112
+ }
113
+ .tw-font-mono {
114
+ font-family:
115
+ ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
116
+ "Liberation Mono", "Courier New", monospace;
117
+ }
118
+ .tw-mt-6 {
119
+ margin-top: 1.5rem;
120
+ }
121
+ .tw-text-4xl {
122
+ font-size: 2.25rem;
123
+ line-height: 2.5rem;
124
+ }
125
+ .tw-h-12 {
126
+ height: 3rem;
127
+ }
128
+ .tw-w-full {
129
+ width: 100%;
130
+ }
131
+ .tw-py-3 {
132
+ padding-top: 0.75rem;
133
+ padding-bottom: 0.75rem;
134
+ }
135
+ .tw-px-4 {
136
+ padding-left: 1rem;
137
+ padding-right: 1rem;
138
+ }
139
+ .tw-bg-slate-900 {
140
+ background-color: #0f172a;
141
+ }
142
+ .tw-text-white {
143
+ color: #ffffff;
144
+ }
145
+ .tw-rounded-xl {
146
+ border-radius: 0.75rem;
147
+ }
148
+ .tw-font-semibold {
149
+ font-weight: 600;
150
+ }
151
+ .tw-shadow-lg {
152
+ box-shadow:
153
+ 0 10px 15px -3px rgba(0, 0, 0, 0.1),
154
+ 0 4px 6px -2px rgba(0, 0, 0, 0.05);
155
+ }
156
+ .tw-absolute {
157
+ position: absolute;
158
+ }
159
+ .tw-top-4 {
160
+ top: 1rem;
161
+ }
162
+ .tw-right-4 {
163
+ right: 1rem;
164
+ }
165
+ .tw-bg-white-20 {
166
+ background-color: rgba(255, 255, 255, 0.2);
167
+ backdrop-filter: blur(12px);
168
+ }
169
+ .tw-p-2 {
170
+ padding: 0.5rem;
171
+ }
172
+ .tw-rounded-full {
173
+ border-radius: 9999px;
174
+ }
175
+ .tw-z-50 {
176
+ z-index: 50;
177
+ }
178
+ button {
179
+ cursor: pointer;
180
+ border: none;
181
+ }
182
+ </style>
183
+
184
+ <!-- MediaPipe Core Only (Injected by React Native locally) -->
185
+ <!-- MEDIAPIPE_LOCAL_INJECT -->
186
+
187
+ <!-- ONNX Runtime -->
188
+ <script src="https://cdn.jsdelivr.net/npm/onnxruntime-web/dist/ort.min.js"></script>
189
+
190
+ <style>
191
+ @keyframes pulse-ring {
192
+ 0% {
193
+ transform: scale(0.95);
194
+ box-shadow: 0 0 0 0 rgba(99, 102, 241, 0.7);
195
+ }
196
+ 70% {
197
+ transform: scale(1);
198
+ box-shadow: 0 0 0 20px rgba(99, 102, 241, 0);
199
+ }
200
+ 100% {
201
+ transform: scale(0.95);
202
+ box-shadow: 0 0 0 0 rgba(99, 102, 241, 0);
203
+ }
204
+ }
205
+
206
+ .camera-circle {
207
+ position: relative;
208
+ width: 320px;
209
+ height: 320px;
210
+ border-radius: 50%;
211
+ overflow: hidden;
212
+ border: 4px solid #e2e8f0;
213
+ box-shadow: 0 10px 30px -10px rgba(0, 0, 0, 0.3);
214
+ margin: 0 auto;
215
+ background: #000;
216
+ }
217
+
218
+ .camera-circle.active {
219
+ border-color: #6366f1;
220
+ /* animation: pulse-ring 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; */
221
+ }
222
+
223
+ .camera-circle.success {
224
+ border-color: #22c55e;
225
+ box-shadow: 0 0 0 8px rgba(34, 197, 94, 0.2);
226
+ }
227
+
228
+ .camera-circle.fail {
229
+ border-color: #ef4444;
230
+ box-shadow: 0 0 0 8px rgba(239, 68, 68, 0.2);
231
+ }
232
+
233
+ #output_canvas {
234
+ width: 100%;
235
+ height: 100%;
236
+ object-fit: cover;
237
+ }
238
+
239
+ .mirror {
240
+ transform: scaleX(-1);
241
+ }
242
+
243
+ /* Progress Bar */
244
+ .progress-container {
245
+ width: 200px;
246
+ height: 6px;
247
+ background: #e2e8f0;
248
+ border-radius: 999px;
249
+ margin: 20px auto;
250
+ overflow: hidden;
251
+ }
252
+
253
+ /* Headless Mode Overrides */
254
+ body.headless-mode {
255
+ background-color: transparent !important;
256
+ }
257
+ body.headless-mode .tw-container {
258
+ max-width: none !important;
259
+ width: 100vw !important;
260
+ height: 100vh !important;
261
+ border-radius: 0 !important;
262
+ box-shadow: none !important;
263
+ padding: 0 !important;
264
+ background-color: transparent !important;
265
+ }
266
+ body.headless-mode .tw-title,
267
+ body.headless-mode .tw-subtitle,
268
+ body.headless-mode #ghost_face,
269
+ body.headless-mode #arrow_left,
270
+ body.headless-mode #arrow_right,
271
+ body.headless-mode #progress_wrapper,
272
+ body.headless-mode #feedback_icon,
273
+ body.headless-mode #btn_retry,
274
+ body.headless-mode #btn_flip {
275
+ display: none !important;
276
+ }
277
+ body.headless-mode .camera-circle {
278
+ width: 100vw !important;
279
+ height: 100vh !important;
280
+ border-radius: 0 !important;
281
+ border: none !important;
282
+ box-shadow: none !important;
283
+ margin: 0 !important;
284
+ position: absolute;
285
+ top: 0;
286
+ left: 0;
287
+ }
288
+ body.headless-mode #output_canvas {
289
+ width: 100%;
290
+ height: 100%;
291
+ object-fit: cover;
292
+ }
293
+
294
+ .progress-bar {
295
+ height: 100%;
296
+ background: #6366f1;
297
+ width: 0%;
298
+ transition: width 0.3s ease;
299
+ }
300
+
301
+ /* Result Image */
302
+ #captured_image {
303
+ width: 100%;
304
+ height: 100%;
305
+ object-fit: cover;
306
+ display: none;
307
+ }
308
+
309
+ /* Visual Guidance */
310
+ .ghost-face {
311
+ position: absolute;
312
+ top: 50%;
313
+ left: 50%;
314
+ transform: translate(-50%, -50%);
315
+ width: 180px;
316
+ height: 240px;
317
+ border: 2px dashed rgba(255, 255, 255, 0.4);
318
+ border-radius: 50% 50% 40% 40%;
319
+ pointer-events: none;
320
+ transition: all 0.3s ease;
321
+ }
322
+
323
+ .ghost-face.active {
324
+ border-color: #6366f1;
325
+ border-style: solid;
326
+ box-shadow: 0 0 20px rgba(99, 102, 241, 0.3);
327
+ }
328
+
329
+ .ghost-face.error {
330
+ border-color: #ef4444;
331
+ animation: pulse-error 1s infinite;
332
+ }
333
+
334
+ @keyframes pulse-error {
335
+ 0% {
336
+ transform: translate(-50%, -50%) scale(1);
337
+ opacity: 1;
338
+ }
339
+ 50% {
340
+ transform: translate(-50%, -50%) scale(1.05);
341
+ opacity: 0.6;
342
+ }
343
+ 100% {
344
+ transform: translate(-50%, -50%) scale(1);
345
+ opacity: 1;
346
+ }
347
+ }
348
+
349
+ .guidance-arrow {
350
+ position: absolute;
351
+ top: 50%;
352
+ font-size: 3rem;
353
+ color: white;
354
+ text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);
355
+ opacity: 0;
356
+ transition: opacity 0.3s;
357
+ pointer-events: none;
358
+ }
359
+
360
+ .arrow-left {
361
+ left: 20px;
362
+ transform: translateY(-50%);
363
+ animation: bounce-left 1s infinite;
364
+ }
365
+
366
+ .arrow-right {
367
+ right: 20px;
368
+ transform: translateY(-50%);
369
+ animation: bounce-right 1s infinite;
370
+ }
371
+
372
+ @keyframes bounce-left {
373
+ 0%,
374
+ 100% {
375
+ transform: translate(0, -50%);
376
+ }
377
+ 50% {
378
+ transform: translate(-10px, -50%);
379
+ }
380
+ }
381
+
382
+ @keyframes bounce-right {
383
+ 0%,
384
+ 100% {
385
+ transform: translate(0, -50%);
386
+ }
387
+ 50% {
388
+ transform: translate(10px, -50%);
389
+ }
390
+ }
391
+ </style>
392
+ </head>
393
+ <body
394
+ class="tw-bg-slate-50 tw-min-h-screen tw-flex tw-items-center tw-justify-center tw-font-sans"
395
+ >
396
+ <div class="tw-container">
397
+ <!-- Header -->
398
+ <h2 class="tw-title">Liveness Check</h2>
399
+ <p id="instruction_text" class="tw-subtitle">Initialize camera...</p>
400
+
401
+ <!-- Camera Frame -->
402
+ <div id="camera_wrapper" class="camera-circle">
403
+ <video id="input_video" class="tw-hidden" playsinline></video>
404
+ <canvas id="output_canvas"></canvas>
405
+
406
+ <!-- Guidance Overlays -->
407
+ <div id="ghost_face" class="ghost-face"></div>
408
+ <div id="arrow_left" class="guidance-arrow arrow-left">⬅️</div>
409
+ <div id="arrow_right" class="guidance-arrow arrow-right">➡️</div>
410
+ </div>
411
+
412
+ <!-- Progress -->
413
+ <div id="progress_wrapper" class="tw-opacity-0 tw-transition">
414
+ <div class="progress-container">
415
+ <div id="progress_bar" class="progress-bar"></div>
416
+ </div>
417
+ <p class="tw-text-xs tw-text-slate-400 tw-font-mono">
418
+ Analyzing Texture...
419
+ </p>
420
+ </div>
421
+
422
+ <!-- Status Icons / Feedback -->
423
+ <div id="feedback_icon" class="tw-mt-6 tw-text-4xl tw-h-12">
424
+ <!-- Dynamic Icons: 😐 🙂 ⬅️ ➡️ ✅ ❌ -->
425
+ 📷
426
+ </div>
427
+
428
+ <!-- Retry Button (Hidden by default) -->
429
+ <button
430
+ id="btn_retry"
431
+ onclick="retryLiveness()"
432
+ class="tw-hidden tw-mt-6 tw-w-full tw-py-3 tw-px-4 tw-bg-slate-900 tw-text-white tw-rounded-xl tw-font-semibold tw-shadow-lg"
433
+ >
434
+ Try Again
435
+ </button>
436
+
437
+ <!-- Camera Toggle -->
438
+ <button
439
+ id="btn_flip"
440
+ onclick="toggleCamera()"
441
+ class="tw-absolute tw-top-4 tw-right-4 tw-bg-white-20 tw-p-2 tw-rounded-full tw-z-50"
442
+ >
443
+ 🔄
444
+ </button>
445
+ </div>
446
+
447
+ <!-- Scripts -->
448
+ <script src="/static/js/onnx_antispoof.js"></script>
449
+ <script src="/static/js/real_liveness.js"></script>
450
+ </body>
451
+ </html>