@daboss2003/liveness-web 1.0.0 → 1.0.2
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.
- package/dist/ui.js +22 -24
- package/package.json +1 -1
- package/src/ui.ts +22 -24
package/dist/ui.js
CHANGED
|
@@ -4,9 +4,10 @@ import { DEFAULT_SOUND_DATA_URLS } from "./default-sounds.generated";
|
|
|
4
4
|
const OVAL_W = 270;
|
|
5
5
|
const OVAL_H = 360;
|
|
6
6
|
const OVAL_TOP_PCT = 40;
|
|
7
|
-
//
|
|
8
|
-
const
|
|
9
|
-
const
|
|
7
|
+
// Progress stroke sits on the main oval: ellipse inset by half stroke so outer edge aligns with cutout
|
|
8
|
+
const STROKE_HALF = 1.75;
|
|
9
|
+
const RX = OVAL_W / 2 - STROKE_HALF;
|
|
10
|
+
const RY = OVAL_H / 2 - STROKE_HALF;
|
|
10
11
|
const ELLIPSE_PERIMETER = Math.PI * (3 * (RX + RY) - Math.sqrt((3 * RX + RY) * (RX + 3 * RY)));
|
|
11
12
|
/** Step label (from engine) → hint icon kind. Use this so the correct icon shows when steps are randomized. */
|
|
12
13
|
const STEP_LABEL_TO_HINT = {
|
|
@@ -40,6 +41,11 @@ function createStyles() {
|
|
|
40
41
|
display: flex;
|
|
41
42
|
flex-direction: column;
|
|
42
43
|
align-items: center;
|
|
44
|
+
/* Radii: keep oval inside viewport on mobile (diameter = 2× this), cap at desktop */
|
|
45
|
+
--oval-w: min(45vmin, ${OVAL_W}px);
|
|
46
|
+
--oval-h: min(60vmin, ${OVAL_H}px);
|
|
47
|
+
/* Half-height of the visible oval for positioning (oval uses full w/h as radii) */
|
|
48
|
+
--oval-half-h: var(--oval-h);
|
|
43
49
|
}
|
|
44
50
|
|
|
45
51
|
/* ── Full-bleed video behind everything ─────────────────────────────── */
|
|
@@ -65,9 +71,9 @@ function createStyles() {
|
|
|
65
71
|
.lv-overlay {
|
|
66
72
|
position: absolute;
|
|
67
73
|
inset: 0;
|
|
68
|
-
/*
|
|
69
|
-
--ow:
|
|
70
|
-
--oh:
|
|
74
|
+
/* Ellipse size (radii): full oval w/h so cutout is large; ring is scaled to match */
|
|
75
|
+
--ow: var(--oval-w);
|
|
76
|
+
--oh: var(--oval-h);
|
|
71
77
|
background: var(--lv-dark);
|
|
72
78
|
-webkit-mask-image: radial-gradient(
|
|
73
79
|
ellipse var(--ow) var(--oh) at 50% ${OVAL_TOP_PCT}%,
|
|
@@ -85,22 +91,17 @@ function createStyles() {
|
|
|
85
91
|
background: rgba(180,0,0,0.55);
|
|
86
92
|
}
|
|
87
93
|
|
|
88
|
-
/* ── Oval SVG ring
|
|
94
|
+
/* ── Oval SVG ring (2× so progress sits on the main oval boundary) ───── */
|
|
89
95
|
.lv-ring-wrap {
|
|
90
96
|
position: absolute;
|
|
91
97
|
left: 50%;
|
|
92
98
|
top: ${OVAL_TOP_PCT}%;
|
|
93
99
|
transform: translate(-50%, -50%);
|
|
94
|
-
width:
|
|
95
|
-
height:
|
|
100
|
+
width: calc(2 * var(--oval-w));
|
|
101
|
+
height: calc(2 * var(--oval-h));
|
|
96
102
|
pointer-events: none;
|
|
97
103
|
}
|
|
98
104
|
.lv-ring-wrap svg { width: 100%; height: 100%; overflow: visible; }
|
|
99
|
-
.lv-ring-track {
|
|
100
|
-
fill: none;
|
|
101
|
-
stroke: rgba(255,255,255,0.15);
|
|
102
|
-
stroke-width: 3.5;
|
|
103
|
-
}
|
|
104
105
|
.lv-ring-progress {
|
|
105
106
|
fill: none;
|
|
106
107
|
stroke: var(--lv-green);
|
|
@@ -134,7 +135,7 @@ function createStyles() {
|
|
|
134
135
|
.lv-dots {
|
|
135
136
|
position: absolute;
|
|
136
137
|
z-index: 2;
|
|
137
|
-
top: calc(${OVAL_TOP_PCT}% +
|
|
138
|
+
top: calc(${OVAL_TOP_PCT}% + var(--oval-half-h) + 20px);
|
|
138
139
|
left: 50%;
|
|
139
140
|
transform: translateX(-50%);
|
|
140
141
|
display: flex;
|
|
@@ -152,7 +153,7 @@ function createStyles() {
|
|
|
152
153
|
.lv-instruction {
|
|
153
154
|
position: absolute;
|
|
154
155
|
z-index: 2;
|
|
155
|
-
top: calc(${OVAL_TOP_PCT}% +
|
|
156
|
+
top: calc(${OVAL_TOP_PCT}% + var(--oval-half-h) + 52px);
|
|
156
157
|
left: 50%;
|
|
157
158
|
transform: translateX(-50%);
|
|
158
159
|
white-space: nowrap;
|
|
@@ -168,7 +169,7 @@ function createStyles() {
|
|
|
168
169
|
.lv-pos-hint {
|
|
169
170
|
position: absolute;
|
|
170
171
|
z-index: 2;
|
|
171
|
-
top: calc(${OVAL_TOP_PCT}% +
|
|
172
|
+
top: calc(${OVAL_TOP_PCT}% + var(--oval-half-h) + 84px);
|
|
172
173
|
left: 50%;
|
|
173
174
|
transform: translateX(-50%);
|
|
174
175
|
font-size: 13px;
|
|
@@ -278,9 +279,6 @@ export function startLivenessWithUI(options) {
|
|
|
278
279
|
ringWrap.className = "lv-ring-wrap";
|
|
279
280
|
ringWrap.innerHTML = `
|
|
280
281
|
<svg viewBox="0 0 ${OVAL_W} ${OVAL_H}">
|
|
281
|
-
<ellipse class="lv-ring-track"
|
|
282
|
-
cx="${rx}" cy="${ry}" rx="${RX}" ry="${RY}"
|
|
283
|
-
pathLength="${ELLIPSE_PERIMETER.toFixed(1)}"/>
|
|
284
282
|
<ellipse class="lv-ring-progress"
|
|
285
283
|
cx="${rx}" cy="${ry}" rx="${RX}" ry="${RY}"
|
|
286
284
|
pathLength="${ELLIPSE_PERIMETER.toFixed(1)}"
|
|
@@ -295,10 +293,10 @@ export function startLivenessWithUI(options) {
|
|
|
295
293
|
hintIcon.setAttribute("aria-hidden", "true");
|
|
296
294
|
root.appendChild(hintIcon);
|
|
297
295
|
// ── Header ─────────────────────────────────────────────────────────────────
|
|
298
|
-
const header = document.createElement("div");
|
|
299
|
-
header.className = "lv-header";
|
|
300
|
-
header.innerHTML = `<span class="lv-header-title">Face Verification</span>`;
|
|
301
|
-
root.appendChild(header);
|
|
296
|
+
// const header = document.createElement("div");
|
|
297
|
+
// header.className = "lv-header";
|
|
298
|
+
// header.innerHTML = `<span class="lv-header-title">Face Verification</span>`;
|
|
299
|
+
// root.appendChild(header);
|
|
302
300
|
// ── Step dots ──────────────────────────────────────────────────────────────
|
|
303
301
|
const dotsEl = document.createElement("div");
|
|
304
302
|
dotsEl.className = "lv-dots";
|
package/package.json
CHANGED
package/src/ui.ts
CHANGED
|
@@ -14,9 +14,10 @@ const OVAL_W = 270;
|
|
|
14
14
|
const OVAL_H = 360;
|
|
15
15
|
const OVAL_TOP_PCT = 40;
|
|
16
16
|
|
|
17
|
-
//
|
|
18
|
-
const
|
|
19
|
-
const
|
|
17
|
+
// Progress stroke sits on the main oval: ellipse inset by half stroke so outer edge aligns with cutout
|
|
18
|
+
const STROKE_HALF = 1.75;
|
|
19
|
+
const RX = OVAL_W / 2 - STROKE_HALF;
|
|
20
|
+
const RY = OVAL_H / 2 - STROKE_HALF;
|
|
20
21
|
const ELLIPSE_PERIMETER = Math.PI * (3 * (RX + RY) - Math.sqrt((3 * RX + RY) * (RX + 3 * RY)));
|
|
21
22
|
|
|
22
23
|
type HintKind = "left" | "blink" | "right" | "nod" | "mouth";
|
|
@@ -55,6 +56,11 @@ function createStyles(): HTMLStyleElement {
|
|
|
55
56
|
display: flex;
|
|
56
57
|
flex-direction: column;
|
|
57
58
|
align-items: center;
|
|
59
|
+
/* Radii: keep oval inside viewport on mobile (diameter = 2× this), cap at desktop */
|
|
60
|
+
--oval-w: min(45vmin, ${OVAL_W}px);
|
|
61
|
+
--oval-h: min(60vmin, ${OVAL_H}px);
|
|
62
|
+
/* Half-height of the visible oval for positioning (oval uses full w/h as radii) */
|
|
63
|
+
--oval-half-h: var(--oval-h);
|
|
58
64
|
}
|
|
59
65
|
|
|
60
66
|
/* ── Full-bleed video behind everything ─────────────────────────────── */
|
|
@@ -80,9 +86,9 @@ function createStyles(): HTMLStyleElement {
|
|
|
80
86
|
.lv-overlay {
|
|
81
87
|
position: absolute;
|
|
82
88
|
inset: 0;
|
|
83
|
-
/*
|
|
84
|
-
--ow:
|
|
85
|
-
--oh:
|
|
89
|
+
/* Ellipse size (radii): full oval w/h so cutout is large; ring is scaled to match */
|
|
90
|
+
--ow: var(--oval-w);
|
|
91
|
+
--oh: var(--oval-h);
|
|
86
92
|
background: var(--lv-dark);
|
|
87
93
|
-webkit-mask-image: radial-gradient(
|
|
88
94
|
ellipse var(--ow) var(--oh) at 50% ${OVAL_TOP_PCT}%,
|
|
@@ -100,22 +106,17 @@ function createStyles(): HTMLStyleElement {
|
|
|
100
106
|
background: rgba(180,0,0,0.55);
|
|
101
107
|
}
|
|
102
108
|
|
|
103
|
-
/* ── Oval SVG ring
|
|
109
|
+
/* ── Oval SVG ring (2× so progress sits on the main oval boundary) ───── */
|
|
104
110
|
.lv-ring-wrap {
|
|
105
111
|
position: absolute;
|
|
106
112
|
left: 50%;
|
|
107
113
|
top: ${OVAL_TOP_PCT}%;
|
|
108
114
|
transform: translate(-50%, -50%);
|
|
109
|
-
width:
|
|
110
|
-
height:
|
|
115
|
+
width: calc(2 * var(--oval-w));
|
|
116
|
+
height: calc(2 * var(--oval-h));
|
|
111
117
|
pointer-events: none;
|
|
112
118
|
}
|
|
113
119
|
.lv-ring-wrap svg { width: 100%; height: 100%; overflow: visible; }
|
|
114
|
-
.lv-ring-track {
|
|
115
|
-
fill: none;
|
|
116
|
-
stroke: rgba(255,255,255,0.15);
|
|
117
|
-
stroke-width: 3.5;
|
|
118
|
-
}
|
|
119
120
|
.lv-ring-progress {
|
|
120
121
|
fill: none;
|
|
121
122
|
stroke: var(--lv-green);
|
|
@@ -149,7 +150,7 @@ function createStyles(): HTMLStyleElement {
|
|
|
149
150
|
.lv-dots {
|
|
150
151
|
position: absolute;
|
|
151
152
|
z-index: 2;
|
|
152
|
-
top: calc(${OVAL_TOP_PCT}% +
|
|
153
|
+
top: calc(${OVAL_TOP_PCT}% + var(--oval-half-h) + 20px);
|
|
153
154
|
left: 50%;
|
|
154
155
|
transform: translateX(-50%);
|
|
155
156
|
display: flex;
|
|
@@ -167,7 +168,7 @@ function createStyles(): HTMLStyleElement {
|
|
|
167
168
|
.lv-instruction {
|
|
168
169
|
position: absolute;
|
|
169
170
|
z-index: 2;
|
|
170
|
-
top: calc(${OVAL_TOP_PCT}% +
|
|
171
|
+
top: calc(${OVAL_TOP_PCT}% + var(--oval-half-h) + 52px);
|
|
171
172
|
left: 50%;
|
|
172
173
|
transform: translateX(-50%);
|
|
173
174
|
white-space: nowrap;
|
|
@@ -183,7 +184,7 @@ function createStyles(): HTMLStyleElement {
|
|
|
183
184
|
.lv-pos-hint {
|
|
184
185
|
position: absolute;
|
|
185
186
|
z-index: 2;
|
|
186
|
-
top: calc(${OVAL_TOP_PCT}% +
|
|
187
|
+
top: calc(${OVAL_TOP_PCT}% + var(--oval-half-h) + 84px);
|
|
187
188
|
left: 50%;
|
|
188
189
|
transform: translateX(-50%);
|
|
189
190
|
font-size: 13px;
|
|
@@ -301,9 +302,6 @@ export function startLivenessWithUI(options: StartLivenessOptions): LivenessEngi
|
|
|
301
302
|
ringWrap.className = "lv-ring-wrap";
|
|
302
303
|
ringWrap.innerHTML = `
|
|
303
304
|
<svg viewBox="0 0 ${OVAL_W} ${OVAL_H}">
|
|
304
|
-
<ellipse class="lv-ring-track"
|
|
305
|
-
cx="${rx}" cy="${ry}" rx="${RX}" ry="${RY}"
|
|
306
|
-
pathLength="${ELLIPSE_PERIMETER.toFixed(1)}"/>
|
|
307
305
|
<ellipse class="lv-ring-progress"
|
|
308
306
|
cx="${rx}" cy="${ry}" rx="${RX}" ry="${RY}"
|
|
309
307
|
pathLength="${ELLIPSE_PERIMETER.toFixed(1)}"
|
|
@@ -320,10 +318,10 @@ export function startLivenessWithUI(options: StartLivenessOptions): LivenessEngi
|
|
|
320
318
|
root.appendChild(hintIcon);
|
|
321
319
|
|
|
322
320
|
// ── Header ─────────────────────────────────────────────────────────────────
|
|
323
|
-
const header = document.createElement("div");
|
|
324
|
-
header.className = "lv-header";
|
|
325
|
-
header.innerHTML = `<span class="lv-header-title">Face Verification</span>`;
|
|
326
|
-
root.appendChild(header);
|
|
321
|
+
// const header = document.createElement("div");
|
|
322
|
+
// header.className = "lv-header";
|
|
323
|
+
// header.innerHTML = `<span class="lv-header-title">Face Verification</span>`;
|
|
324
|
+
// root.appendChild(header);
|
|
327
325
|
|
|
328
326
|
// ── Step dots ──────────────────────────────────────────────────────────────
|
|
329
327
|
const dotsEl = document.createElement("div");
|