@jaak.ai/stamps 2.2.0-dev.9 → 2.3.0-dev.1
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/README.md +188 -8
- package/dist/cjs/jaak-stamps.cjs.entry.js +124 -25
- package/dist/cjs/jaak-stamps.cjs.entry.js.map +1 -1
- package/dist/cjs/jaak-stamps.entry.cjs.js.map +1 -1
- package/dist/collection/components/my-component/my-component.css +23 -2
- package/dist/collection/components/my-component/my-component.js +44 -16
- package/dist/collection/components/my-component/my-component.js.map +1 -1
- package/dist/collection/services/CameraService.js +41 -9
- package/dist/collection/services/CameraService.js.map +1 -1
- package/dist/collection/services/LicenseValidationService.js +1 -1
- package/dist/collection/services/LicenseValidationService.js.map +1 -1
- package/dist/collection/services/factories/DeviceStrategyFactory.js +7 -0
- package/dist/collection/services/factories/DeviceStrategyFactory.js.map +1 -1
- package/dist/collection/services/strategies/IOSSafariStrategy.js +33 -0
- package/dist/collection/services/strategies/IOSSafariStrategy.js.map +1 -0
- package/dist/components/jaak-stamps.js +124 -25
- package/dist/components/jaak-stamps.js.map +1 -1
- package/dist/esm/jaak-stamps.entry.js +124 -25
- package/dist/esm/jaak-stamps.entry.js.map +1 -1
- package/dist/jaak-stamps-webcomponent/jaak-stamps-webcomponent.esm.js +1 -1
- package/dist/jaak-stamps-webcomponent/jaak-stamps.entry.esm.js.map +1 -1
- package/dist/jaak-stamps-webcomponent/p-04f57d50.entry.js +7 -0
- package/dist/jaak-stamps-webcomponent/p-04f57d50.entry.js.map +1 -0
- package/dist/types/components/my-component/my-component.d.ts +2 -1
- package/dist/types/components.d.ts +2 -2
- package/dist/types/services/LicenseValidationService.d.ts +1 -1
- package/dist/types/services/strategies/IOSSafariStrategy.d.ts +12 -0
- package/package.json +1 -1
- package/dist/jaak-stamps-webcomponent/p-dfecb452.entry.js +0 -7
- package/dist/jaak-stamps-webcomponent/p-dfecb452.entry.js.map +0 -1
package/README.md
CHANGED
|
@@ -56,23 +56,49 @@ yarn add @jaak.ai/stamps
|
|
|
56
56
|
|
|
57
57
|
### Properties/Attributes
|
|
58
58
|
|
|
59
|
+
#### License Properties (Required)
|
|
60
|
+
|
|
59
61
|
| Property | Type | Default | Description |
|
|
60
62
|
|----------|------|---------|-------------|
|
|
61
|
-
| `license` | `string` | `undefined` | License key for component authentication
|
|
62
|
-
| `environment` | `'dev' \| 'qa' \| '
|
|
63
|
-
| `trace-id` | `string` | `undefined` | Optional trace ID for request tracing (auto-generated if not provided) |
|
|
63
|
+
| `license` | `string` | `undefined` | **[REQUIRED]** License key for component authentication |
|
|
64
|
+
| `license-environment` | `'dev' \| 'qa' \| 'sandbox' \| 'prod'` | `'prod'` | API environment for license validation |
|
|
64
65
|
| `app-id` | `string` | `'jaak-stamps-web'` | Application identifier for analytics and tracking |
|
|
66
|
+
| `trace-id` | `string` | `undefined` | Optional trace ID for distributed tracing (auto-generated if not provided) |
|
|
67
|
+
|
|
68
|
+
#### Base Configuration Properties
|
|
69
|
+
|
|
70
|
+
| Property | Type | Default | Description |
|
|
71
|
+
|----------|------|---------|-------------|
|
|
65
72
|
| `debug` | `boolean` | `false` | Enable debug mode with additional logging and overlays |
|
|
66
|
-
| `mask-size` | `number` | `90` | Size percentage of the document detection mask |
|
|
67
|
-
| `alignment-tolerance` | `number` | `15` | Tolerance level for document alignment detection |
|
|
68
|
-
| `capture-delay` | `number` | `1500` | Delay in milliseconds before automatic capture |
|
|
69
|
-
| `crop-margin` | `number` | `20` | Margin in pixels around detected document for cropping |
|
|
73
|
+
| `mask-size` | `number` | `90` | Size percentage of the document detection mask (50-100) |
|
|
74
|
+
| `alignment-tolerance` | `number` | `15` | Tolerance level in pixels for document alignment detection |
|
|
75
|
+
| `capture-delay` | `number` | `1500` | Delay in milliseconds before automatic capture (0-10000) |
|
|
76
|
+
| `crop-margin` | `number` | `20` | Margin in pixels around detected document for cropping (0-100) |
|
|
70
77
|
| `preferred-camera` | `'auto' \| 'front' \| 'back'` | `'auto'` | Preferred camera selection |
|
|
71
|
-
| `use-document-classification` | `boolean` | `false` | Enable AI document classification |
|
|
78
|
+
| `use-document-classification` | `boolean` | `false` | Enable AI document type classification |
|
|
72
79
|
| `use-document-detector` | `boolean` | `true` | Enable/disable AI document detection model |
|
|
73
80
|
| `enable-back-document-timer` | `boolean` | `false` | Enable timer for back document capture |
|
|
74
81
|
| `back-document-timer-duration` | `number` | `20` | Duration in seconds for back document capture timer |
|
|
75
82
|
|
|
83
|
+
#### Telemetry and OpenTelemetry Properties
|
|
84
|
+
|
|
85
|
+
| Property | Type | Default | Description |
|
|
86
|
+
|----------|------|---------|-------------|
|
|
87
|
+
| `telemetry-collector-url` | `string` | `'https://collector.jaak.ai/v1/traces'` | OTLP collector URL for distributed traces |
|
|
88
|
+
| `metrics-collector-url` | `string` | `'https://collector.jaak.ai/v1/metrics'` | OTLP collector URL for metrics |
|
|
89
|
+
| `enable-telemetry` | `boolean` | `true` | Enable distributed tracing with OpenTelemetry |
|
|
90
|
+
| `enable-metrics` | `boolean` | `true` | Enable metrics export to OpenTelemetry |
|
|
91
|
+
| `metrics-export-interval-millis` | `number` | `60000` | Metrics export interval in milliseconds |
|
|
92
|
+
| `propagate-trace-header-cors-urls` | `string` | `undefined` | Comma-separated URLs for W3C Trace Context header propagation |
|
|
93
|
+
|
|
94
|
+
#### Context Properties
|
|
95
|
+
|
|
96
|
+
| Property | Type | Default | Description |
|
|
97
|
+
|----------|------|---------|-------------|
|
|
98
|
+
| `customer-id` | `string` | `undefined` | Customer ID for telemetry and analytics |
|
|
99
|
+
| `tenant-id` | `string` | `undefined` | Tenant ID for multi-tenancy support |
|
|
100
|
+
| `environment` | `string` | `'production'` | Execution environment (development/staging/production) |
|
|
101
|
+
|
|
76
102
|
### Methods
|
|
77
103
|
|
|
78
104
|
#### Camera Control
|
|
@@ -581,6 +607,160 @@ import { DocumentScannerComponent } from './document-scanner.component';
|
|
|
581
607
|
export class DocumentScannerModule { }
|
|
582
608
|
```
|
|
583
609
|
|
|
610
|
+
## Telemetry and Observability (OpenTelemetry)
|
|
611
|
+
|
|
612
|
+
Jaak Stamps includes full **OpenTelemetry** integration for distributed tracing, metrics, and performance monitoring in production environments.
|
|
613
|
+
|
|
614
|
+
### Distributed Tracing
|
|
615
|
+
|
|
616
|
+
The component implements distributed tracing following the **W3C Trace Context** standard, providing:
|
|
617
|
+
|
|
618
|
+
- Complete flow tracking of document capture processes
|
|
619
|
+
- Request correlation between frontend and backend
|
|
620
|
+
- Performance bottleneck identification
|
|
621
|
+
- Context propagation via `traceparent` headers
|
|
622
|
+
|
|
623
|
+
**Automatically Recorded Spans:**
|
|
624
|
+
- `component.initialize` - Component initialization
|
|
625
|
+
- `capture.start` - Capture process start
|
|
626
|
+
- `model.preload` - AI model preloading
|
|
627
|
+
- `model.detection.load` - Detection model loading
|
|
628
|
+
- `model.classification.load` - Classification model loading
|
|
629
|
+
|
|
630
|
+
### Performance Metrics
|
|
631
|
+
|
|
632
|
+
The component exports detailed metrics to OpenTelemetry:
|
|
633
|
+
|
|
634
|
+
**Counters:**
|
|
635
|
+
- `capture.counter` - Number of completed captures
|
|
636
|
+
- `error.counter` - Error count by type
|
|
637
|
+
- `model.load.counter` - Model load count
|
|
638
|
+
- `user.interaction.counter` - User interactions
|
|
639
|
+
|
|
640
|
+
**Histograms (Latencies):**
|
|
641
|
+
- `capture.latency` - Total capture time
|
|
642
|
+
- `model.load.latency` - Model loading time
|
|
643
|
+
- `detection.latency` - Per-frame detection time
|
|
644
|
+
- `image.size` - Captured image sizes
|
|
645
|
+
|
|
646
|
+
**Gauges (Current State):**
|
|
647
|
+
- `active.sessions` - Active sessions
|
|
648
|
+
- `memory.usage` - Memory usage
|
|
649
|
+
|
|
650
|
+
### Telemetry Configuration
|
|
651
|
+
|
|
652
|
+
```html
|
|
653
|
+
<jaak-stamps
|
|
654
|
+
license="your-license-key"
|
|
655
|
+
enable-telemetry="true"
|
|
656
|
+
enable-metrics="true"
|
|
657
|
+
telemetry-collector-url="https://collector.jaak.ai/v1/traces"
|
|
658
|
+
metrics-collector-url="https://collector.jaak.ai/v1/metrics"
|
|
659
|
+
metrics-export-interval-millis="60000"
|
|
660
|
+
propagate-trace-header-cors-urls="https://api.example.com,https://backend.example.com"
|
|
661
|
+
customer-id="customer123"
|
|
662
|
+
tenant-id="tenant456"
|
|
663
|
+
environment="production"
|
|
664
|
+
trace-id="optional-custom-trace-id">
|
|
665
|
+
</jaak-stamps>
|
|
666
|
+
```
|
|
667
|
+
|
|
668
|
+
### Using Trace ID
|
|
669
|
+
|
|
670
|
+
The component automatically generates a unique trace ID for each session, or accepts a custom one:
|
|
671
|
+
|
|
672
|
+
```javascript
|
|
673
|
+
const scanner = document.getElementById('documentScanner');
|
|
674
|
+
|
|
675
|
+
// Listen for trace ID generation
|
|
676
|
+
scanner.addEventListener('traceIdGenerated', (event) => {
|
|
677
|
+
const traceId = event.detail.traceId;
|
|
678
|
+
console.log('Trace ID for this session:', traceId);
|
|
679
|
+
|
|
680
|
+
// Use this traceId to correlate requests in your backend
|
|
681
|
+
fetch('/api/process-document', {
|
|
682
|
+
method: 'POST',
|
|
683
|
+
headers: {
|
|
684
|
+
'X-Trace-Id': traceId,
|
|
685
|
+
'Content-Type': 'application/json'
|
|
686
|
+
},
|
|
687
|
+
body: JSON.stringify({ /* data */ })
|
|
688
|
+
});
|
|
689
|
+
});
|
|
690
|
+
```
|
|
691
|
+
|
|
692
|
+
### Enriched Attributes
|
|
693
|
+
|
|
694
|
+
Traces and metrics automatically include:
|
|
695
|
+
|
|
696
|
+
- **User Agent:** Browser, version, operating system
|
|
697
|
+
- **Geolocation:** Country, region, city (when available)
|
|
698
|
+
- **Device Memory:** Device memory capacity
|
|
699
|
+
- **Customer Context:** `customerId`, `tenantId`, `environment`
|
|
700
|
+
- **Service Info:** Service name, component version
|
|
701
|
+
|
|
702
|
+
### Context Propagation (CORS)
|
|
703
|
+
|
|
704
|
+
To propagate traces to your backend services:
|
|
705
|
+
|
|
706
|
+
```html
|
|
707
|
+
<jaak-stamps
|
|
708
|
+
propagate-trace-header-cors-urls="https://api.example.com,https://services.example.com">
|
|
709
|
+
</jaak-stamps>
|
|
710
|
+
```
|
|
711
|
+
|
|
712
|
+
This automatically configures `fetch` and `XMLHttpRequest` interceptors to include the `traceparent` header in requests to those URLs.
|
|
713
|
+
|
|
714
|
+
### Visualization with Jaeger/Zipkin
|
|
715
|
+
|
|
716
|
+
Exported traces are compatible with:
|
|
717
|
+
- **Jaeger** - Distributed tracing system
|
|
718
|
+
- **Zipkin** - Alternative tracing system
|
|
719
|
+
- **Grafana Tempo** - Grafana trace backend
|
|
720
|
+
- Any OTLP-compatible backend (OpenTelemetry Protocol)
|
|
721
|
+
|
|
722
|
+
## License Validation
|
|
723
|
+
|
|
724
|
+
The component **requires a valid license** to function. Validation occurs automatically when the component loads.
|
|
725
|
+
|
|
726
|
+
### License Configuration
|
|
727
|
+
|
|
728
|
+
```html
|
|
729
|
+
<jaak-stamps
|
|
730
|
+
license="your-license-key-here"
|
|
731
|
+
license-environment="prod"
|
|
732
|
+
app-id="my-application">
|
|
733
|
+
</jaak-stamps>
|
|
734
|
+
```
|
|
735
|
+
|
|
736
|
+
### Available Environments
|
|
737
|
+
|
|
738
|
+
| Environment | Validation URL | Use Case |
|
|
739
|
+
|-------------|---------------|----------|
|
|
740
|
+
| `dev` | `https://api.dev.jaak.ai` | Local development |
|
|
741
|
+
| `qa` | `https://api.qa.jaak.ai` | Quality assurance testing |
|
|
742
|
+
| `sandbox` | `https://api.sandbox.jaak.ai` | Integration testing |
|
|
743
|
+
| `prod` | `https://services.api.jaak.ai` | Production |
|
|
744
|
+
|
|
745
|
+
### License Error Handling
|
|
746
|
+
|
|
747
|
+
If the license is invalid, the component will display an error and not function:
|
|
748
|
+
|
|
749
|
+
```javascript
|
|
750
|
+
const scanner = document.getElementById('documentScanner');
|
|
751
|
+
|
|
752
|
+
scanner.addEventListener('isReady', (event) => {
|
|
753
|
+
if (!event.detail) {
|
|
754
|
+
console.error('Error: Invalid license or component not initialized');
|
|
755
|
+
}
|
|
756
|
+
});
|
|
757
|
+
```
|
|
758
|
+
|
|
759
|
+
**Common error messages:**
|
|
760
|
+
- `"License key is required"` - No license provided
|
|
761
|
+
- `"Invalid license key"` - Invalid or expired license
|
|
762
|
+
- `"License validation failed"` - Validation error
|
|
763
|
+
|
|
584
764
|
## Style Guide
|
|
585
765
|
|
|
586
766
|
### CSS Custom Properties
|
|
@@ -532,17 +532,30 @@ class CameraService {
|
|
|
532
532
|
}
|
|
533
533
|
const constraints = { ...videoConstraints };
|
|
534
534
|
if (capabilities.width && capabilities.height) {
|
|
535
|
-
const maxWidth = Math.min(capabilities.width.max, 1920);
|
|
536
|
-
const maxHeight = Math.min(capabilities.height.max, 1080);
|
|
537
535
|
const isTablet = /iPad|Android/i.test(navigator.userAgent) && window.innerWidth >= 768;
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
536
|
+
const isMobileDevice = this.deviceType === 'mobile' ||
|
|
537
|
+
/Android|iPhone|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
|
|
538
|
+
// Optimize resolution based on device type to prevent "slow motion" effect
|
|
539
|
+
// on devices with high-resolution cameras
|
|
540
|
+
let targetWidth;
|
|
541
|
+
let targetHeight;
|
|
542
|
+
if (isMobileDevice && !isTablet) {
|
|
543
|
+
// Mobile phones: Use 720p max to ensure smooth detection performance
|
|
544
|
+
targetWidth = Math.min(capabilities.width.max, 1280);
|
|
545
|
+
targetHeight = Math.min(capabilities.height.max, 720);
|
|
546
|
+
}
|
|
547
|
+
else if (isTablet) {
|
|
548
|
+
// Tablets: Can handle slightly higher resolution
|
|
549
|
+
targetWidth = Math.min(capabilities.width.max, 1280);
|
|
550
|
+
targetHeight = Math.min(capabilities.height.max, 720);
|
|
541
551
|
}
|
|
542
552
|
else {
|
|
543
|
-
|
|
544
|
-
|
|
553
|
+
// Desktop: Can handle full HD
|
|
554
|
+
targetWidth = Math.min(capabilities.width.max, 1920);
|
|
555
|
+
targetHeight = Math.min(capabilities.height.max, 1080);
|
|
545
556
|
}
|
|
557
|
+
constraints.width = { ideal: targetWidth };
|
|
558
|
+
constraints.height = { ideal: targetHeight };
|
|
546
559
|
}
|
|
547
560
|
// Configure autofocus if camera has the capability
|
|
548
561
|
const capabilitiesAny = capabilities;
|
|
@@ -562,9 +575,28 @@ class CameraService {
|
|
|
562
575
|
await this.detectDeviceType();
|
|
563
576
|
}
|
|
564
577
|
const isTablet = /iPad|Android/i.test(navigator.userAgent) && window.innerWidth >= 768;
|
|
578
|
+
const isMobileDevice = this.deviceType === 'mobile' ||
|
|
579
|
+
/Android|iPhone|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
|
|
580
|
+
// Optimized fallback constraints for device type
|
|
581
|
+
let fallbackWidth;
|
|
582
|
+
let fallbackHeight;
|
|
583
|
+
if (isMobileDevice && !isTablet) {
|
|
584
|
+
// Mobile phones: Use 720p for smooth performance
|
|
585
|
+
fallbackWidth = 1280;
|
|
586
|
+
fallbackHeight = 720;
|
|
587
|
+
}
|
|
588
|
+
else if (isTablet) {
|
|
589
|
+
fallbackWidth = 1280;
|
|
590
|
+
fallbackHeight = 720;
|
|
591
|
+
}
|
|
592
|
+
else {
|
|
593
|
+
// Desktop
|
|
594
|
+
fallbackWidth = 1920;
|
|
595
|
+
fallbackHeight = 1080;
|
|
596
|
+
}
|
|
565
597
|
const fallbackConstraints = {
|
|
566
|
-
width: { ideal:
|
|
567
|
-
height: { ideal:
|
|
598
|
+
width: { ideal: fallbackWidth },
|
|
599
|
+
height: { ideal: fallbackHeight }
|
|
568
600
|
};
|
|
569
601
|
if (this.selectedCameraId) {
|
|
570
602
|
fallbackConstraints.deviceId = { exact: this.selectedCameraId };
|
|
@@ -697,9 +729,48 @@ class HighPerformanceDeviceStrategy {
|
|
|
697
729
|
}
|
|
698
730
|
}
|
|
699
731
|
|
|
732
|
+
/**
|
|
733
|
+
* Strategy for iOS Safari to prevent jetsam memory kills.
|
|
734
|
+
* WebKit 26+ has a known bug with ONNX Runtime JSEP mode that causes memory exhaustion.
|
|
735
|
+
* This strategy forces pure WASM execution without GPU acceleration.
|
|
736
|
+
* See: https://github.com/microsoft/onnxruntime/issues/26827
|
|
737
|
+
*/
|
|
738
|
+
class IOSSafariStrategy {
|
|
739
|
+
getDeviceInfo() {
|
|
740
|
+
return {
|
|
741
|
+
estimatedRAM: 3, // Assume low memory for iOS
|
|
742
|
+
isLowMemory: true,
|
|
743
|
+
isSlowConnection: false
|
|
744
|
+
};
|
|
745
|
+
}
|
|
746
|
+
getSessionOptions(_debug) {
|
|
747
|
+
return {
|
|
748
|
+
// Force pure WASM - no WebGL, no WebGPU, no JSEP
|
|
749
|
+
executionProviders: ['wasm'],
|
|
750
|
+
graphOptimizationLevel: 'disabled', // Disable graph optimization to reduce memory
|
|
751
|
+
logSeverityLevel: 4,
|
|
752
|
+
logVerbosityLevel: 0,
|
|
753
|
+
enableCpuMemArena: false, // Don't use CPU memory arena
|
|
754
|
+
enableMemPattern: false, // Don't use memory pattern optimization
|
|
755
|
+
executionMode: 'sequential', // Sequential execution uses less memory
|
|
756
|
+
interOpNumThreads: 1, // Single thread
|
|
757
|
+
intraOpNumThreads: 1, // Single thread
|
|
758
|
+
};
|
|
759
|
+
}
|
|
760
|
+
shouldUseSequentialLoading() {
|
|
761
|
+
return true;
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
|
|
700
765
|
class DeviceStrategyFactory {
|
|
701
766
|
static createStrategy() {
|
|
702
767
|
const nav = navigator;
|
|
768
|
+
const ua = navigator.userAgent;
|
|
769
|
+
// iOS Safari requires special handling due to WebKit memory constraints
|
|
770
|
+
const isIOSSafari = /iPad|iPhone|iPod/.test(ua) && /Safari/.test(ua) && !/CriOS|FxiOS|OPiOS|EdgiOS/.test(ua);
|
|
771
|
+
if (isIOSSafari) {
|
|
772
|
+
return new IOSSafariStrategy();
|
|
773
|
+
}
|
|
703
774
|
const memory = nav.deviceMemory || nav.hardwareConcurrency || 4;
|
|
704
775
|
const isLowMemory = memory <= 4;
|
|
705
776
|
if (isLowMemory) {
|
|
@@ -18459,7 +18530,7 @@ class LicenseValidationService {
|
|
|
18459
18530
|
static ENVIRONMENT_URLS = {
|
|
18460
18531
|
dev: 'https://api.dev.jaak.ai',
|
|
18461
18532
|
qa: 'https://api.qa.jaak.ai',
|
|
18462
|
-
|
|
18533
|
+
sandbox: 'https://api.sandbox.jaak.ai',
|
|
18463
18534
|
prod: 'https://services.api.jaak.ai',
|
|
18464
18535
|
};
|
|
18465
18536
|
constructor(environment = 'prod') {
|
|
@@ -18559,7 +18630,7 @@ class LicenseValidationService {
|
|
|
18559
18630
|
}
|
|
18560
18631
|
}
|
|
18561
18632
|
|
|
18562
|
-
const myComponentCss = ":host{display:block;width:100%;height:100%;font-family:system-ui, -apple-system, sans-serif;color:#1a1a1a}.detector-container{display:flex;flex-direction:column;align-items:center;width:100%;height:100%}h1{font-size:24px;font-weight:500;color:#333;margin:0 0 24px 0}.video-container{position:relative;width:100%;height:100%;background:#333;border:1px solid #e0e0e0;border-radius:8px;overflow:hidden}video,.detection-overlay{position:absolute;width:100%;height:100%;border-radius:8px}video.mirror,.detection-overlay.mirror{transform:rotateY(180deg)}.detection-overlay{z-index:1;pointer-events:none}video{z-index:0}.detection-box{transition:opacity 0.2s ease}.status{margin-top:16px;font-size:12px;color:#666}.overlay-mask{position:absolute;top:0;left:0;width:100%;height:100%;z-index:10;display:block;pointer-events:none}.card-outline{position:absolute;top:var(--mask-center-y, 50%);left:var(--mask-center-x, 50%);transform:translate(-50%, -50%);width:var(--mask-width, 88%);height:var(--mask-height, 55%);border:none;border-radius:4px;background:transparent;opacity:0.8}.side{position:absolute;background:#999;transition:background-color 0.3s ease;border-radius:1px}.side-top.aligned{border-left-color:#28a745;border-top-color:#28a745}.side-right.aligned{border-right-color:#28a745;border-top-color:#28a745}.side-bottom.aligned{border-left-color:#28a745;border-bottom-color:#28a745}.side-left.aligned{border-right-color:#28a745;border-bottom-color:#28a745}.side-top{top:-3px;left:-3px;width:30px;height:30px;border-left:6px solid #ffffff;border-top:6px solid #ffffff;background:transparent}.side-right{top:-3px;right:-3px;width:30px;height:30px;border-right:6px solid #ffffff;border-top:6px solid #ffffff;background:transparent}.side-bottom{bottom:-3px;left:-3px;width:30px;height:30px;border-left:6px solid #ffffff;border-bottom:6px solid #ffffff;background:transparent}.side-left{bottom:-3px;right:-3px;width:30px;height:30px;border-right:6px solid #ffffff;border-bottom:6px solid #ffffff;background:transparent}.guide-text{position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(20px);border-radius:12px;border:1px solid rgba(255, 255, 255, 0.1);color:#ffffff;font-size:12px;font-weight:500;text-align:center;white-space:normal;padding:13px;max-width:300px;z-index:20;height:fit-content;width:fit-content;animation:slideInFromTopCentered 0.3s ease-out}.quality-indicator{position:absolute;top:20px;right:20px;display:flex;align-items:center;gap:8px;background:rgba(0, 0, 0, 0.8);padding:8px 12px;border-radius:20px;z-index:25;transition:all 0.3s ease}.quality-indicator.warning{background:rgba(255, 152, 0, 0.9)}.quality-indicator.good{background:rgba(76, 175, 80, 0.9)}.quality-score{color:#fff;font-size:12px;font-weight:600;min-width:30px;text-align:center}.quality-status{width:20px;height:20px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:14px;font-weight:bold;color:#fff;transition:all 0.3s ease}.quality-status.ready{background:#4CAF50}.quality-status.not-ready{background:#f44336}.card-outline.quality-warning{animation:qualityWarning 1s ease-in-out infinite alternate}@keyframes qualityWarning{0%{box-shadow:0 0 0 3px rgba(255, 152, 0, 0.6)}100%{box-shadow:0 0 0 6px rgba(255, 152, 0, 0.3)}}.capture-animation{position:absolute;top:0;left:0;width:100%;height:100%;background:#fff;opacity:0;z-index:30;pointer-events:none;animation:captureFlash 0.6s ease-out}@keyframes captureFlash{0%{opacity:0}15%{opacity:0.8}30%{opacity:0}45%{opacity:0.4}60%{opacity:0}100%{opacity:0}}.card-outline.capturing{animation:pulseGreen 0.6s ease-out}@keyframes pulseGreen{0%{border-color:#28a745;box-shadow:0 0 0 4px rgba(40, 167, 69, 0)}50%{border-color:#28a745;box-shadow:0 0 0 8px rgba(40, 167, 69, 0.6)}100%{border-color:#28a745;box-shadow:0 0 0 4px rgba(40, 167, 69, 0)}}.flip-animation{position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);z-index:35;pointer-events:none;opacity:0;animation:showFlipInstruction 3s ease-in-out;display:flex;flex-direction:column;align-items:center;justify-content:center}.id-card-icon{width:80px;height:50px;background:linear-gradient(135deg, #6c757d 0%, #495057 100%);border-radius:8px;position:relative;animation:flipCard 2s ease-in-out infinite;box-shadow:0 4px 12px rgba(0, 0, 0, 0.3)}.id-card-icon::before{content:'';position:absolute;top:8px;left:8px;width:16px;height:12px;background:rgba(255, 255, 255, 0.9);border-radius:2px}.id-card-icon::after{content:'';position:absolute;top:25px;left:8px;width:64px;height:3px;background:rgba(255, 255, 255, 0.7);border-radius:1px;box-shadow:0 6px 0 rgba(255, 255, 255, 0.7), 0 12px 0 rgba(255, 255, 255, 0.7)}.flip-text{margin-top:12px;color:#fff;font-size:14px;font-weight:600;text-align:center;background:rgba(128, 128, 128, 0.8);padding:12px 20px;border-radius:20px;max-width:300px}@keyframes showFlipInstruction{0%{opacity:0;transform:translate(-50%, -50%) scale(0.8)}15%{opacity:1;transform:translate(-50%, -50%) scale(1)}85%{opacity:1;transform:translate(-50%, -50%) scale(1)}100%{opacity:0;transform:translate(-50%, -50%) scale(0.8)}}@keyframes flipCard{0%{transform:rotateY(0deg)}50%{transform:rotateY(180deg)}100%{transform:rotateY(360deg)}}.success-animation{position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);z-index:35;pointer-events:none;opacity:0;animation:showSuccessMessage 3s ease-in-out;display:flex;flex-direction:column;align-items:center;justify-content:center}.check-icon{width:80px;height:80px;background:linear-gradient(135deg, #6c757d 0%, #495057 100%);border-radius:50%;position:relative;animation:bounceSuccess 0.6s ease-out;box-shadow:0 4px 16px rgba(108, 117, 125, 0.4);display:flex;align-items:center;justify-content:center}.check-icon::before{content:'';position:absolute;width:20px;height:35px;border:4px solid #fff;border-top:none;border-left:none;transform:rotate(45deg);}.success-text{margin-top:16px;color:#fff;font-size:14px;font-weight:600;text-align:center;background:rgba(128, 128, 128, 0.8);padding:12px 20px;border-radius:20px;max-width:300px;animation:fadeInUp 0.5s ease-out 0.4s both}@keyframes showSuccessMessage{0%{opacity:0;transform:translate(-50%, -50%) scale(0.5)}15%{opacity:1;transform:translate(-50%, -50%) scale(1)}85%{opacity:1;transform:translate(-50%, -50%) scale(1)}100%{opacity:0;transform:translate(-50%, -50%) scale(0.9)}}@keyframes bounceSuccess{0%{transform:scale(0)}50%{transform:scale(1.1)}100%{transform:scale(1)}}@keyframes drawCheck{0%{width:0;height:0}50%{width:20px;height:0}100%{width:20px;height:35px}}@keyframes fadeInUp{0%{opacity:0;transform:translateY(20px)}100%{opacity:1;transform:translateY(0)}}.skip-section{position:absolute;bottom:20px;left:50%;transform:translateX(-50%);z-index:25;display:flex;flex-direction:column;align-items:center;width:100%;max-width:300px}.back-capture-section{position:absolute;bottom:20px;left:50%;transform:translateX(-50%);z-index:25;display:flex;flex-direction:column;align-items:center;width:100%;max-width:320px}.back-capture-buttons{display:flex;gap:12px;align-items:center;justify-content:center;flex-wrap:wrap}.capture-button{pointer-events:auto;background:#fff;color:#333;border:none;border-radius:25px;padding:12px 24px;font-size:14px;font-weight:600;cursor:pointer;transition:all 0.3s ease}.capture-button:hover{background:#f8f9fa}.capture-button:active{background:#e9ecef;transform:translateY(1px)}.capture-button:disabled,.capture-button.primary-button:disabled{cursor:not-allowed !important;transform:none !important;opacity:0.7 !important;transition:none !important}@media (max-width: 480px){.back-capture-section{bottom:16px;max-width:300px}.back-capture-buttons{flex-direction:column;gap:8px;width:100%}.capture-button,.back-capture-buttons .skip-button{width:100%;max-width:200px;padding:10px 20px;font-size:13px}.capture-button:disabled,.capture-button.primary-button:disabled,.skip-button:disabled{opacity:0.7 !important;cursor:not-allowed !important}}.skip-explanation{background:rgba(0, 0, 0, 0.5);color:#ffffff;padding:10px 16px;border-radius:8px;font-size:14px;font-weight:500;text-align:center;margin-bottom:12px;box-shadow:0 2px 8px rgba(0, 0, 0, 0.2);backdrop-filter:blur(12px);border:1px solid rgba(255, 255, 255, 0.1);animation:fadeIn 0.3s ease-in-out}@keyframes fadeIn{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}.guide-text.performance-warning-text{animation:gentlePulse 2s ease-in-out infinite;background:rgba(255, 107, 107, 0.3);border:1px solid rgba(255, 107, 107, 0.5)}@keyframes gentlePulse{0%,100%{transform:translate(-50%, -50%) scale(1);background:rgba(255, 107, 107, 0.3)}50%{transform:translate(-50%, -50%) scale(1.02);background:rgba(255, 107, 107, 0.4)}}.skip-button{pointer-events:auto;background:#fff;color:#333;border:none;border-radius:25px;padding:12px 24px;font-size:14px;font-weight:600;cursor:pointer;transition:all 0.3s ease}.skip-button:hover{background:#f8f9fa}.skip-button:active{background:#e9ecef;transform:translateY(1px)}.skip-button:disabled{cursor:not-allowed !important;transform:none !important;opacity:0.7 !important;transition:none !important}.camera-controls{position:absolute;top:16px;right:16px;z-index:25;display:flex;gap:8px;pointer-events:auto;animation:slideInFromTop 0.3s ease-out}.camera-selector-button{height:32px;padding:0 10px;border:none;border-radius:8px;background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(12px);color:#ffffff;font-size:12px;font-weight:500;cursor:pointer;transition:all 0.2s ease;display:flex;align-items:center;justify-content:center;border:1px solid rgba(255, 255, 255, 0.1);white-space:nowrap;min-width:fit-content}.camera-selector-button:hover{background:rgba(0, 0, 0, 0.8);border-color:rgba(255, 255, 255, 0.2);transform:translateY(-1px)}.camera-selector-button:active{transform:translateY(0);background:rgba(0, 0, 0, 0.9)}.camera-selector-button:disabled,.camera-selector-button.loading{opacity:0.7;cursor:not-allowed;pointer-events:none}.camera-selector-button:disabled:hover,.camera-selector-button.loading:hover{transform:none;background:rgba(0, 0, 0, 0.6);border-color:rgba(255, 255, 255, 0.1)}.button-spinner{width:16px;height:16px;border:2px solid rgba(0, 0, 0, 0.2);border-top:2px solid #333333;border-radius:50%;animation:spin 1s linear infinite;display:inline-block;margin-right:8px;vertical-align:middle}@keyframes spin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}.camera-selector-dropdown{position:absolute;top:56px;right:16px;z-index:30;background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(20px);border-radius:12px;min-width:260px;max-width:300px;border:1px solid rgba(255, 255, 255, 0.1);overflow:hidden;pointer-events:auto;animation:slideInFromTop 0.3s ease-out}@keyframes slideInFromTop{0%{opacity:0;transform:translateY(-8px) scale(0.95)}100%{opacity:1;transform:translateY(0) scale(1)}}@keyframes slideInFromTopCentered{0%{opacity:0;transform:translate(-50%, -50%) translateY(-8px) scale(0.95)}100%{opacity:1;transform:translate(-50%, -50%) translateY(0) scale(1)}}.camera-selector-header{display:flex;justify-content:space-between;align-items:center;padding:8px 12px;border-bottom:1px solid rgba(255, 255, 255, 0.1)}.camera-selector-header span{font-weight:500;color:#ffffff;font-size:13px;opacity:0.9}.close-selector{width:20px;height:20px;border:none;background:none;color:rgba(255, 255, 255, 0.7);font-size:16px;cursor:pointer;display:flex;align-items:center;justify-content:center;border-radius:4px;transition:all 0.2s ease}.close-selector:hover{background:rgba(255, 255, 255, 0.1);color:#ffffff}.camera-list{padding:4px 0;max-height:240px;overflow-y:auto}.camera-option{width:100%;padding:8px 12px;border:none;background:none;text-align:left;cursor:pointer;transition:all 0.2s ease;display:flex;justify-content:flex-start;align-items:center;gap:8px;color:rgba(255, 255, 255, 0.9)}.camera-option:hover{background:rgba(255, 255, 255, 0.08)}.camera-option.selected{background:rgba(255, 255, 255, 0.12);color:#ffffff}.camera-label{font-size:13px;flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-right:0;font-weight:400;display:flex;align-items:center;gap:6px}.camera-label .autofocus-icon{font-size:12px;color:#ffffff !important;opacity:0.8;flex-shrink:0}.selected-indicator{font-size:14px;color:#ffffff;opacity:0.9;flex-shrink:0}.device-info{padding:6px 12px;border-top:1px solid rgba(255, 255, 255, 0.1);background:rgba(255, 255, 255, 0.05)}.device-info small{color:rgba(255, 255, 255, 0.6);font-size:11px;text-transform:capitalize;font-weight:400}@media (max-width: 480px){.camera-controls{top:12px;right:12px;gap:6px}.camera-selector-button{height:36px;padding:0 12px;font-size:11px;border-radius:6px}.camera-selector-dropdown{right:12px;top:48px;min-width:240px;max-width:calc(100vw - 24px)}.camera-selector-header{padding:6px 10px}.camera-option{padding:6px 10px}.device-info{padding:4px 10px}}.watermark{position:absolute;bottom:12px;right:12px;z-index:15;pointer-events:none;opacity:0.7}.watermark img{height:24px;width:auto;filter:drop-shadow(0 1px 2px rgba(0, 0, 0, 0.3))}.component-status{position:absolute;top:16px;left:16px;background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(20px);border-radius:12px;border:1px solid rgba(255, 255, 255, 0.1);display:flex;align-items:center;gap:6px;padding:6px 10px;z-index:40;height:32px;width:fit-content;animation:slideInFromTop 0.3s ease-out}.status-spinner{width:16px;height:16px;border:1px solid rgba(255, 255, 255, 0.3);border-top:1px solid #ffffff;border-radius:50%;animation:statusSpin 1s linear infinite;flex-shrink:0}.status-content{display:flex;flex-direction:column;gap:1px}.status-message{color:#ffffff;font-size:12px;font-weight:500;margin:0}.status-description{color:rgba(255, 255, 255, 0.7);font-size:10px;line-height:1.2;margin:0}@keyframes statusSpin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}@media (max-width: 480px){.component-status{top:12px;left:12px;padding:4px 8px;gap:4px;height:28px;border-radius:8px}.status-spinner{width:14px;height:14px}.status-message{font-size:11px}.status-description{font-size:9px}.guide-text{font-size:11px;padding:4px 8px;border-radius:8px}}.loading-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background:rgba(0, 0, 0, 0.85);backdrop-filter:blur(4px);display:flex;flex-direction:column;align-items:center;justify-content:center;z-index:30;border-radius:8px}.loading-spinner{width:50px;height:50px;border:3px solid rgba(255, 255, 255, 0.15);border-top:3px solid #28a745;border-radius:50%;animation:spin 1s ease-in-out infinite;margin-bottom:16px}.loading-text{color:#ffffff;font-size:14px;font-weight:500;text-align:center;opacity:0.9;margin-bottom:4px}.loading-description{color:rgba(255, 255, 255, 0.7);font-size:12px;text-align:center;opacity:0.8}@keyframes spin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}.performance-monitor{position:absolute;top:70px;left:16px;background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(20px);border-radius:12px;border:1px solid rgba(255, 255, 255, 0.1);z-index:35;width:fit-content;animation:slideInFromTop 0.3s ease-out;transition:all 0.3s ease}@keyframes slideInFromLeft{0%{opacity:0;transform:translateX(-20px) scale(0.95)}100%{opacity:1;transform:translateX(0) scale(1)}}.performance-expanded{padding:6px 10px}.metrics-row{display:flex;gap:8px;margin-bottom:4px}.metrics-row:last-child{margin-bottom:0}.metric-compact{display:flex;flex-direction:column;align-items:center;gap:2px;min-width:50px}.metric-label{font-size:9px;color:rgba(255, 255, 255, 0.6);font-weight:500;text-transform:uppercase;letter-spacing:0.3px}.metric-value{font-size:10px;font-weight:600;font-family:'Monaco', 'Menlo', 'Consolas', monospace;padding:2px 4px;border-radius:3px;text-align:center;white-space:nowrap}.metric-value.good{color:#4ade80;background:rgba(74, 222, 128, 0.1);border:1px solid rgba(74, 222, 128, 0.2)}.metric-value.warning{color:#fbbf24;background:rgba(251, 191, 36, 0.1);border:1px solid rgba(251, 191, 36, 0.2)}.metric-value.danger{color:#f87171;background:rgba(248, 113, 113, 0.1);border:1px solid rgba(248, 113, 113, 0.2)}@media (max-width: 480px){.performance-monitor{top:60px;left:12px;width:fit-content}.performance-expanded{padding:4px 8px}.metrics-row{gap:6px;margin-bottom:3px}.metric-compact{min-width:45px;gap:1px}.metric-label{font-size:8px}.metric-value{font-size:9px;padding:1px 3px}}.quality-monitor{position:absolute;top:200px;left:16px;background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(20px);border-radius:12px;border:1px solid rgba(255, 255, 255, 0.1);z-index:35;width:fit-content;animation:slideInFromLeft 0.3s ease-out;transition:all 0.3s ease}.quality-text{padding:6px 10px;font-size:11px;color:white;font-family:'Monaco', 'Menlo', 'Consolas', monospace;line-height:1.4}.quality-fail{color:#ff9999}@keyframes pulse{0%,100%{opacity:1}50%{opacity:0.7}}.metric-value.danger{animation:pulse 2s infinite}@media (max-width: 480px){.quality-monitor{top:160px;left:12px}.quality-text{padding:4px 8px;font-size:10px}}.manual-capture-section{position:absolute;bottom:20px;left:50%;transform:translateX(-50%);z-index:25;display:flex;flex-direction:column;align-items:center;width:100%;max-width:300px}.manual-capture-button{pointer-events:auto;background:#fff;color:#333;border:none;border-radius:25px;padding:12px 24px;font-size:14px;font-weight:600;cursor:pointer;transition:all 0.3s ease}.manual-capture-button:hover{background:#f8f9fa}.manual-capture-button:active{background:#e9ecef;transform:translateY(1px)}.manual-capture-button:disabled{cursor:not-allowed !important;transform:none !important;opacity:0.7 !important;transition:none !important}@media (max-width: 480px){.manual-capture-section{bottom:16px;max-width:280px}.manual-capture-button{padding:10px 20px;font-size:13px}.manual-capture-button:disabled{opacity:0.7 !important;cursor:not-allowed !important}}.license-error-container{display:flex;align-items:center;justify-content:center;padding:40px 20px;height:100%;width:100%;background:#f5f7fa;font-family:-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif}.license-error-card{background:#ffffff;border-radius:8px;box-shadow:0 2px 12px rgba(0, 0, 0, 0.1);max-width:480px;width:100%;padding:48px 32px;text-align:center}.license-error-icon{color:#dc3545;margin-bottom:24px}.license-error-title{color:#2c3e50;font-size:24px;font-weight:600;margin:0 0 16px 0}.license-error-message{color:#495057;font-size:16px;line-height:1.6;margin:0 0 24px 0}.license-error-help{color:#6c757d;font-size:14px;margin:0 0 32px 0}.license-error-help a{color:#007bff;text-decoration:none;font-weight:500}.license-error-help a:hover{text-decoration:underline}.license-error-footer{color:#adb5bd;font-size:12px;font-weight:500;padding-top:24px;border-top:1px solid #e9ecef}@media (max-width: 640px){.license-error-card{padding:32px 24px}.license-error-title{font-size:20px}.license-error-message{font-size:14px}}";
|
|
18633
|
+
const myComponentCss = ":host{display:block;width:100%;height:100%;font-family:system-ui, -apple-system, sans-serif;color:#1a1a1a}.detector-container{display:flex;flex-direction:column;align-items:center;width:100%;height:100%}h1{font-size:24px;font-weight:500;color:#333;margin:0 0 24px 0}.video-container{position:relative;width:100%;height:100%;background-color:#000;border:none;border-radius:8px;overflow:hidden}video,.detection-overlay{position:absolute;width:100%;height:100%;border-radius:8px}video.mirror,.detection-overlay.mirror{transform:rotateY(180deg)}.detection-overlay{z-index:1;pointer-events:none}video{z-index:0}video::-webkit-media-controls{display:none !important}video::-webkit-media-controls-panel{display:none !important}video::-webkit-media-controls-play-button{display:none !important}video::-webkit-media-controls-start-playback-button{display:none !important}video::-webkit-media-controls-enclosure{display:none !important}.detection-box{transition:opacity 0.2s ease}.status{margin-top:16px;font-size:12px;color:#666}.overlay-mask{position:absolute;top:0;left:0;width:100%;height:100%;z-index:10;display:block;pointer-events:none}.card-outline{position:absolute;top:var(--mask-center-y, 50%);left:var(--mask-center-x, 50%);transform:translate(-50%, -50%);width:var(--mask-width, 88%);height:var(--mask-height, 55%);border:none;border-radius:4px;background:transparent;opacity:0.8}.side{position:absolute;background:#999;transition:background-color 0.3s ease;border-radius:1px}.side-top.aligned{border-left-color:#28a745;border-top-color:#28a745}.side-right.aligned{border-right-color:#28a745;border-top-color:#28a745}.side-bottom.aligned{border-left-color:#28a745;border-bottom-color:#28a745}.side-left.aligned{border-right-color:#28a745;border-bottom-color:#28a745}.side-top{top:-3px;left:-3px;width:30px;height:30px;border-left:6px solid #ffffff;border-top:6px solid #ffffff;background:transparent}.side-right{top:-3px;right:-3px;width:30px;height:30px;border-right:6px solid #ffffff;border-top:6px solid #ffffff;background:transparent}.side-bottom{bottom:-3px;left:-3px;width:30px;height:30px;border-left:6px solid #ffffff;border-bottom:6px solid #ffffff;background:transparent}.side-left{bottom:-3px;right:-3px;width:30px;height:30px;border-right:6px solid #ffffff;border-bottom:6px solid #ffffff;background:transparent}.guide-text{position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(20px);border-radius:12px;border:1px solid rgba(255, 255, 255, 0.1);color:#ffffff;font-size:12px;font-weight:500;text-align:center;white-space:normal;padding:13px;max-width:300px;z-index:20;height:fit-content;width:fit-content;animation:slideInFromTopCentered 0.3s ease-out}.quality-indicator{position:absolute;top:20px;right:20px;display:flex;align-items:center;gap:8px;background:rgba(0, 0, 0, 0.8);padding:8px 12px;border-radius:20px;z-index:25;transition:all 0.3s ease}.quality-indicator.warning{background:rgba(255, 152, 0, 0.9)}.quality-indicator.good{background:rgba(76, 175, 80, 0.9)}.quality-score{color:#fff;font-size:12px;font-weight:600;min-width:30px;text-align:center}.quality-status{width:20px;height:20px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:14px;font-weight:bold;color:#fff;transition:all 0.3s ease}.quality-status.ready{background:#4CAF50}.quality-status.not-ready{background:#f44336}.card-outline.quality-warning{animation:qualityWarning 1s ease-in-out infinite alternate}@keyframes qualityWarning{0%{box-shadow:0 0 0 3px rgba(255, 152, 0, 0.6)}100%{box-shadow:0 0 0 6px rgba(255, 152, 0, 0.3)}}.capture-animation{position:absolute;top:0;left:0;width:100%;height:100%;background:#fff;opacity:0;z-index:30;pointer-events:none;animation:captureFlash 0.6s ease-out}@keyframes captureFlash{0%{opacity:0}15%{opacity:0.8}30%{opacity:0}45%{opacity:0.4}60%{opacity:0}100%{opacity:0}}.card-outline.capturing{animation:pulseGreen 0.6s ease-out}@keyframes pulseGreen{0%{border-color:#28a745;box-shadow:0 0 0 4px rgba(40, 167, 69, 0)}50%{border-color:#28a745;box-shadow:0 0 0 8px rgba(40, 167, 69, 0.6)}100%{border-color:#28a745;box-shadow:0 0 0 4px rgba(40, 167, 69, 0)}}.flip-animation{position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);z-index:35;pointer-events:none;opacity:0;animation:showFlipInstruction 3s ease-in-out;display:flex;flex-direction:column;align-items:center;justify-content:center}.id-card-icon{width:80px;height:50px;background:linear-gradient(135deg, #6c757d 0%, #495057 100%);border-radius:8px;position:relative;animation:flipCard 2s ease-in-out infinite;box-shadow:0 4px 12px rgba(0, 0, 0, 0.3)}.id-card-icon::before{content:'';position:absolute;top:8px;left:8px;width:16px;height:12px;background:rgba(255, 255, 255, 0.9);border-radius:2px}.id-card-icon::after{content:'';position:absolute;top:25px;left:8px;width:64px;height:3px;background:rgba(255, 255, 255, 0.7);border-radius:1px;box-shadow:0 6px 0 rgba(255, 255, 255, 0.7), 0 12px 0 rgba(255, 255, 255, 0.7)}.flip-text{margin-top:12px;color:#fff;font-size:14px;font-weight:600;text-align:center;background:rgba(128, 128, 128, 0.8);padding:12px 20px;border-radius:20px;max-width:300px}@keyframes showFlipInstruction{0%{opacity:0;transform:translate(-50%, -50%) scale(0.8)}15%{opacity:1;transform:translate(-50%, -50%) scale(1)}85%{opacity:1;transform:translate(-50%, -50%) scale(1)}100%{opacity:0;transform:translate(-50%, -50%) scale(0.8)}}@keyframes flipCard{0%{transform:rotateY(0deg)}50%{transform:rotateY(180deg)}100%{transform:rotateY(360deg)}}.success-animation{position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);z-index:35;pointer-events:none;opacity:0;animation:showSuccessMessage 3s ease-in-out;display:flex;flex-direction:column;align-items:center;justify-content:center}.check-icon{width:80px;height:80px;background:linear-gradient(135deg, #6c757d 0%, #495057 100%);border-radius:50%;position:relative;animation:bounceSuccess 0.6s ease-out;box-shadow:0 4px 16px rgba(108, 117, 125, 0.4);display:flex;align-items:center;justify-content:center}.check-icon::before{content:'';position:absolute;width:20px;height:35px;border:4px solid #fff;border-top:none;border-left:none;transform:rotate(45deg);}.success-text{margin-top:16px;color:#fff;font-size:14px;font-weight:600;text-align:center;background:rgba(128, 128, 128, 0.8);padding:12px 20px;border-radius:20px;max-width:300px;animation:fadeInUp 0.5s ease-out 0.4s both}@keyframes showSuccessMessage{0%{opacity:0;transform:translate(-50%, -50%) scale(0.5)}15%{opacity:1;transform:translate(-50%, -50%) scale(1)}85%{opacity:1;transform:translate(-50%, -50%) scale(1)}100%{opacity:0;transform:translate(-50%, -50%) scale(0.9)}}@keyframes bounceSuccess{0%{transform:scale(0)}50%{transform:scale(1.1)}100%{transform:scale(1)}}@keyframes drawCheck{0%{width:0;height:0}50%{width:20px;height:0}100%{width:20px;height:35px}}@keyframes fadeInUp{0%{opacity:0;transform:translateY(20px)}100%{opacity:1;transform:translateY(0)}}.skip-section{position:absolute;bottom:20px;left:50%;transform:translateX(-50%);z-index:25;display:flex;flex-direction:column;align-items:center;width:100%;max-width:300px}.back-capture-section{position:absolute;bottom:20px;left:50%;transform:translateX(-50%);z-index:25;display:flex;flex-direction:column;align-items:center;width:100%;max-width:320px}.back-capture-buttons{display:flex;gap:12px;align-items:center;justify-content:center;flex-wrap:wrap}.capture-button{pointer-events:auto;background:#fff;color:#333;border:none;border-radius:25px;padding:12px 24px;font-size:14px;font-weight:600;cursor:pointer;transition:all 0.3s ease}.capture-button:hover{background:#f8f9fa}.capture-button:active{background:#e9ecef;transform:translateY(1px)}.capture-button:disabled,.capture-button.primary-button:disabled{cursor:not-allowed !important;transform:none !important;opacity:0.7 !important;transition:none !important}@media (max-width: 480px){.back-capture-section{bottom:16px;max-width:300px}.back-capture-buttons{flex-direction:column;gap:8px;width:100%}.capture-button,.back-capture-buttons .skip-button{width:100%;max-width:200px;padding:10px 20px;font-size:13px}.capture-button:disabled,.capture-button.primary-button:disabled,.skip-button:disabled{opacity:0.7 !important;cursor:not-allowed !important}}.skip-explanation{background:rgba(0, 0, 0, 0.5);color:#ffffff;padding:10px 16px;border-radius:8px;font-size:14px;font-weight:500;text-align:center;margin-bottom:12px;box-shadow:0 2px 8px rgba(0, 0, 0, 0.2);backdrop-filter:blur(12px);border:1px solid rgba(255, 255, 255, 0.1);animation:fadeIn 0.3s ease-in-out}@keyframes fadeIn{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}.guide-text.performance-warning-text{animation:gentlePulse 2s ease-in-out infinite;background:rgba(255, 107, 107, 0.3);border:1px solid rgba(255, 107, 107, 0.5)}@keyframes gentlePulse{0%,100%{transform:translate(-50%, -50%) scale(1);background:rgba(255, 107, 107, 0.3)}50%{transform:translate(-50%, -50%) scale(1.02);background:rgba(255, 107, 107, 0.4)}}.skip-button{pointer-events:auto;background:#fff;color:#333;border:none;border-radius:25px;padding:12px 24px;font-size:14px;font-weight:600;cursor:pointer;transition:all 0.3s ease}.skip-button:hover{background:#f8f9fa}.skip-button:active{background:#e9ecef;transform:translateY(1px)}.skip-button:disabled{cursor:not-allowed !important;transform:none !important;opacity:0.7 !important;transition:none !important}.camera-controls{position:absolute;top:16px;right:16px;z-index:25;display:flex;gap:8px;pointer-events:auto;animation:slideInFromTop 0.3s ease-out}.camera-selector-button{height:32px;padding:0 10px;border:none;border-radius:8px;background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(12px);color:#ffffff;font-size:12px;font-weight:500;cursor:pointer;transition:all 0.2s ease;display:flex;align-items:center;justify-content:center;border:1px solid rgba(255, 255, 255, 0.1);white-space:nowrap;min-width:fit-content}.camera-selector-button:hover{background:rgba(0, 0, 0, 0.8);border-color:rgba(255, 255, 255, 0.2);transform:translateY(-1px)}.camera-selector-button:active{transform:translateY(0);background:rgba(0, 0, 0, 0.9)}.camera-selector-button:disabled,.camera-selector-button.loading{opacity:0.7;cursor:not-allowed;pointer-events:none}.camera-selector-button:disabled:hover,.camera-selector-button.loading:hover{transform:none;background:rgba(0, 0, 0, 0.6);border-color:rgba(255, 255, 255, 0.1)}.button-spinner{width:16px;height:16px;border:2px solid rgba(0, 0, 0, 0.2);border-top:2px solid #333333;border-radius:50%;animation:spin 1s linear infinite;display:inline-block;margin-right:8px;vertical-align:middle}@keyframes spin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}.camera-selector-dropdown{position:absolute;top:56px;right:16px;z-index:30;background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(20px);border-radius:12px;min-width:260px;max-width:300px;border:1px solid rgba(255, 255, 255, 0.1);overflow:hidden;pointer-events:auto;animation:slideInFromTop 0.3s ease-out}@keyframes slideInFromTop{0%{opacity:0;transform:translateY(-8px) scale(0.95)}100%{opacity:1;transform:translateY(0) scale(1)}}@keyframes slideInFromTopCentered{0%{opacity:0;transform:translate(-50%, -50%) translateY(-8px) scale(0.95)}100%{opacity:1;transform:translate(-50%, -50%) translateY(0) scale(1)}}.camera-selector-header{display:flex;justify-content:space-between;align-items:center;padding:8px 12px;border-bottom:1px solid rgba(255, 255, 255, 0.1)}.camera-selector-header span{font-weight:500;color:#ffffff;font-size:13px;opacity:0.9}.close-selector{width:20px;height:20px;border:none;background:none;color:rgba(255, 255, 255, 0.7);font-size:16px;cursor:pointer;display:flex;align-items:center;justify-content:center;border-radius:4px;transition:all 0.2s ease}.close-selector:hover{background:rgba(255, 255, 255, 0.1);color:#ffffff}.camera-list{padding:4px 0;max-height:240px;overflow-y:auto}.camera-option{width:100%;padding:8px 12px;border:none;background:none;text-align:left;cursor:pointer;transition:all 0.2s ease;display:flex;justify-content:flex-start;align-items:center;gap:8px;color:rgba(255, 255, 255, 0.9)}.camera-option:hover{background:rgba(255, 255, 255, 0.08)}.camera-option.selected{background:rgba(255, 255, 255, 0.12);color:#ffffff}.camera-label{font-size:13px;flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-right:0;font-weight:400;display:flex;align-items:center;gap:6px}.camera-label .autofocus-icon{font-size:12px;color:#ffffff !important;opacity:0.8;flex-shrink:0}.selected-indicator{font-size:14px;color:#ffffff;opacity:0.9;flex-shrink:0}.device-info{padding:6px 12px;border-top:1px solid rgba(255, 255, 255, 0.1);background:rgba(255, 255, 255, 0.05)}.device-info small{color:rgba(255, 255, 255, 0.6);font-size:11px;text-transform:capitalize;font-weight:400}@media (max-width: 480px){.camera-controls{top:12px;right:12px;gap:6px}.camera-selector-button{height:36px;padding:0 12px;font-size:11px;border-radius:6px}.camera-selector-dropdown{right:12px;top:48px;min-width:240px;max-width:calc(100vw - 24px)}.camera-selector-header{padding:6px 10px}.camera-option{padding:6px 10px}.device-info{padding:4px 10px}}.watermark{position:absolute;bottom:12px;right:12px;z-index:15;pointer-events:none;opacity:0.7}.watermark img{height:24px;width:auto;filter:drop-shadow(0 1px 2px rgba(0, 0, 0, 0.3))}.component-status{position:absolute;top:16px;left:16px;background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(20px);border-radius:12px;border:1px solid rgba(255, 255, 255, 0.1);display:flex;align-items:center;gap:6px;padding:6px 10px;z-index:40;height:32px;width:fit-content;animation:slideInFromTop 0.3s ease-out}.status-spinner{width:16px;height:16px;border:1px solid rgba(255, 255, 255, 0.3);border-top:1px solid #ffffff;border-radius:50%;animation:statusSpin 1s linear infinite;flex-shrink:0}.status-content{display:flex;flex-direction:column;gap:1px}.status-message{color:#ffffff;font-size:12px;font-weight:500;margin:0}.status-description{color:rgba(255, 255, 255, 0.7);font-size:10px;line-height:1.2;margin:0}@keyframes statusSpin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}@media (max-width: 480px){.component-status{top:12px;left:12px;padding:4px 8px;gap:4px;height:28px;border-radius:8px}.status-spinner{width:14px;height:14px}.status-message{font-size:11px}.status-description{font-size:9px}.guide-text{font-size:11px;padding:4px 8px;border-radius:8px}}.loading-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background:rgba(0, 0, 0, 0.85);backdrop-filter:blur(4px);display:flex;flex-direction:column;align-items:center;justify-content:center;z-index:30;border-radius:8px}.loading-spinner{width:50px;height:50px;border:3px solid rgba(255, 255, 255, 0.15);border-top:3px solid #28a745;border-radius:50%;animation:spin 1s ease-in-out infinite;margin-bottom:16px}.loading-text{color:#ffffff;font-size:14px;font-weight:500;text-align:center;opacity:0.9;margin-bottom:4px}.loading-description{color:rgba(255, 255, 255, 0.7);font-size:12px;text-align:center;opacity:0.8}@keyframes spin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}.performance-monitor{position:absolute;top:70px;left:16px;background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(20px);border-radius:12px;border:1px solid rgba(255, 255, 255, 0.1);z-index:35;width:fit-content;animation:slideInFromTop 0.3s ease-out;transition:all 0.3s ease}@keyframes slideInFromLeft{0%{opacity:0;transform:translateX(-20px) scale(0.95)}100%{opacity:1;transform:translateX(0) scale(1)}}.performance-expanded{padding:6px 10px}.metrics-row{display:flex;gap:8px;margin-bottom:4px}.metrics-row:last-child{margin-bottom:0}.metric-compact{display:flex;flex-direction:column;align-items:center;gap:2px;min-width:50px}.metric-label{font-size:9px;color:rgba(255, 255, 255, 0.6);font-weight:500;text-transform:uppercase;letter-spacing:0.3px}.metric-value{font-size:10px;font-weight:600;font-family:'Monaco', 'Menlo', 'Consolas', monospace;padding:2px 4px;border-radius:3px;text-align:center;white-space:nowrap}.metric-value.good{color:#4ade80;background:rgba(74, 222, 128, 0.1);border:1px solid rgba(74, 222, 128, 0.2)}.metric-value.warning{color:#fbbf24;background:rgba(251, 191, 36, 0.1);border:1px solid rgba(251, 191, 36, 0.2)}.metric-value.danger{color:#f87171;background:rgba(248, 113, 113, 0.1);border:1px solid rgba(248, 113, 113, 0.2)}@media (max-width: 480px){.performance-monitor{top:60px;left:12px;width:fit-content}.performance-expanded{padding:4px 8px}.metrics-row{gap:6px;margin-bottom:3px}.metric-compact{min-width:45px;gap:1px}.metric-label{font-size:8px}.metric-value{font-size:9px;padding:1px 3px}}.quality-monitor{position:absolute;top:200px;left:16px;background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(20px);border-radius:12px;border:1px solid rgba(255, 255, 255, 0.1);z-index:35;width:fit-content;animation:slideInFromLeft 0.3s ease-out;transition:all 0.3s ease}.quality-text{padding:6px 10px;font-size:11px;color:white;font-family:'Monaco', 'Menlo', 'Consolas', monospace;line-height:1.4}.quality-fail{color:#ff9999}@keyframes pulse{0%,100%{opacity:1}50%{opacity:0.7}}.metric-value.danger{animation:pulse 2s infinite}@media (max-width: 480px){.quality-monitor{top:160px;left:12px}.quality-text{padding:4px 8px;font-size:10px}}.manual-capture-section{position:absolute;bottom:20px;left:50%;transform:translateX(-50%);z-index:25;display:flex;flex-direction:column;align-items:center;width:100%;max-width:300px}.manual-capture-button{pointer-events:auto;background:#fff;color:#333;border:none;border-radius:25px;padding:12px 24px;font-size:14px;font-weight:600;cursor:pointer;transition:all 0.3s ease}.manual-capture-button:hover{background:#f8f9fa}.manual-capture-button:active{background:#e9ecef;transform:translateY(1px)}.manual-capture-button:disabled{cursor:not-allowed !important;transform:none !important;opacity:0.7 !important;transition:none !important}@media (max-width: 480px){.manual-capture-section{bottom:16px;max-width:280px}.manual-capture-button{padding:10px 20px;font-size:13px}.manual-capture-button:disabled{opacity:0.7 !important;cursor:not-allowed !important}}.license-error-container{display:flex;align-items:center;justify-content:center;padding:40px 20px;height:100%;width:100%;background:#f5f7fa;font-family:-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif}.license-error-card{background:#ffffff;border-radius:8px;box-shadow:0 2px 12px rgba(0, 0, 0, 0.1);max-width:480px;width:100%;padding:48px 32px;text-align:center}.license-error-icon{color:#dc3545;margin-bottom:24px}.license-error-title{color:#2c3e50;font-size:24px;font-weight:600;margin:0 0 16px 0}.license-error-message{color:#495057;font-size:16px;line-height:1.6;margin:0 0 24px 0}.license-error-help{color:#6c757d;font-size:14px;margin:0 0 32px 0}.license-error-help a{color:#007bff;text-decoration:none;font-weight:500}.license-error-help a:hover{text-decoration:underline}.license-error-footer{color:#adb5bd;font-size:12px;font-weight:500;padding-top:24px;border-top:1px solid #e9ecef}@media (max-width: 640px){.license-error-card{padding:32px 24px}.license-error-title{font-size:20px}.license-error-message{font-size:14px}}";
|
|
18563
18634
|
|
|
18564
18635
|
const JaakStamps = class {
|
|
18565
18636
|
constructor(hostRef) {
|
|
@@ -18679,6 +18750,7 @@ const JaakStamps = class {
|
|
|
18679
18750
|
MAX_FAILURES = 30;
|
|
18680
18751
|
lastInferenceTime = 0;
|
|
18681
18752
|
MIN_INFERENCE_INTERVAL = 50;
|
|
18753
|
+
MOBILE_MIN_INFERENCE_INTERVAL = 100; // Higher interval for mobile to prevent slow motion
|
|
18682
18754
|
performanceHistory = [];
|
|
18683
18755
|
PERFORMANCE_HISTORY_SIZE = 10;
|
|
18684
18756
|
// Sistema simplificado de monitoreo de rendimiento
|
|
@@ -18843,10 +18915,25 @@ const JaakStamps = class {
|
|
|
18843
18915
|
if (!window.ort) {
|
|
18844
18916
|
this.updateStatus('Preparando herramientas...', 'Configurando funciones de captura', 'initializing');
|
|
18845
18917
|
const script = document.createElement('script');
|
|
18846
|
-
|
|
18918
|
+
// iOS Safari uses WASM-only build to prevent memory issues (WebKit 26+ bug)
|
|
18919
|
+
const ua = navigator.userAgent;
|
|
18920
|
+
const isIOSSafari = /iPad|iPhone|iPod/.test(ua) && /Safari/.test(ua) && !/CriOS|FxiOS|OPiOS|EdgiOS/.test(ua);
|
|
18921
|
+
if (isIOSSafari) {
|
|
18922
|
+
script.src = 'https://cdn.jsdelivr.net/npm/onnxruntime-web@1.23.0/dist/ort.wasm.min.js';
|
|
18923
|
+
}
|
|
18924
|
+
else {
|
|
18925
|
+
script.src = 'https://cdn.jsdelivr.net/npm/onnxruntime-web@1.23.0/dist/ort.min.js';
|
|
18926
|
+
}
|
|
18847
18927
|
document.head.appendChild(script);
|
|
18848
18928
|
await new Promise((resolve) => {
|
|
18849
18929
|
script.onload = () => {
|
|
18930
|
+
// Configure ONNX for iOS Safari low memory mode
|
|
18931
|
+
if (isIOSSafari && window.ort?.env) {
|
|
18932
|
+
const ort = window.ort;
|
|
18933
|
+
ort.env.wasm.simd = false;
|
|
18934
|
+
ort.env.wasm.numThreads = 1;
|
|
18935
|
+
ort.env.wasm.proxy = false;
|
|
18936
|
+
}
|
|
18850
18937
|
setTimeout(async () => {
|
|
18851
18938
|
await this.finalizeInitialization();
|
|
18852
18939
|
resolve(undefined);
|
|
@@ -19543,9 +19630,14 @@ const JaakStamps = class {
|
|
|
19543
19630
|
return;
|
|
19544
19631
|
}
|
|
19545
19632
|
this.frameSkipCounter = 0;
|
|
19546
|
-
// Throttle inference
|
|
19633
|
+
// Throttle inference - use higher interval for mobile devices to prevent slow motion effect
|
|
19547
19634
|
const currentTime = Date.now();
|
|
19548
|
-
|
|
19635
|
+
const isMobileDevice = this.cameraInfoWithAutofocus.deviceType === 'mobile' ||
|
|
19636
|
+
/Android|iPhone|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
|
|
19637
|
+
const isTablet = this.cameraInfoWithAutofocus.deviceType === 'tablet' ||
|
|
19638
|
+
(/iPad|Android/i.test(navigator.userAgent) && window.innerWidth >= 768);
|
|
19639
|
+
const minInterval = (isMobileDevice && !isTablet) ? this.MOBILE_MIN_INFERENCE_INTERVAL : this.MIN_INFERENCE_INTERVAL;
|
|
19640
|
+
if (currentTime - this.lastInferenceTime < minInterval) {
|
|
19549
19641
|
if (captureState.step !== 'completed') {
|
|
19550
19642
|
this.animationId = requestAnimationFrame(() => this.detectFrame());
|
|
19551
19643
|
}
|
|
@@ -19698,7 +19790,7 @@ const JaakStamps = class {
|
|
|
19698
19790
|
isCapturing: false
|
|
19699
19791
|
};
|
|
19700
19792
|
const cameraInfo = this.cameraInfoWithAutofocus;
|
|
19701
|
-
return (index.h("div", { key: '
|
|
19793
|
+
return (index.h("div", { key: 'dc3aed0b4d2d84039b4a123d4bdfe484ea3320ef', class: "detector-container" }, !this.licenseValid && this.licenseError && (index.h("div", { key: 'a9da275905e2d051252f191be944675781632d10', class: "license-error-container" }, index.h("div", { key: 'a36f7408f0d862edd1183ba813c64d9be91f15c6', class: "license-error-card" }, index.h("svg", { key: 'a8e5f3eefc224e16fb62fc0b6d152c85cee249d1', class: "license-error-icon", width: "64", height: "64", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, index.h("path", { key: 'f645fb46a62004309dee1ede871d980c104fedc5', d: "M12 22C12 22 20 18 20 12V5L12 2L4 5V12C4 18 12 22 12 22Z", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }), index.h("path", { key: 'ee472eb3d17cddf46bef7e96561296ff6fbb1aed', d: "M12 8V12", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round" }), index.h("circle", { key: 'c58c787c6c9e307159b3103fdd240e282823aa2f', cx: "12", cy: "16", r: "0.5", fill: "currentColor", stroke: "currentColor", "stroke-width": "1" })), index.h("h2", { key: 'f737ae630fb7661d12a17b7e48cb2c3a1cb6cb4e', class: "license-error-title" }, "Licencia Requerida"), index.h("p", { key: 'fb5cf8d815cddc79f7b5e9ff39f34852a43bc976', class: "license-error-message" }, this.licenseError), index.h("p", { key: 'b47831ee55110b100aa0ea9cbe21d39d2fc19306', class: "license-error-help" }, "Contacte a soporte: ", index.h("a", { key: '52eb8dea1dfdc989b921134f57f1f3f188429061', href: "mailto:support@jaak.ai" }, "support@jaak.ai")), index.h("div", { key: 'fd78565f67049165236694de5ddd415421d0063e', class: "license-error-footer" }, "JAAK Stamps")))), this.licenseValid && (index.h("div", { key: '19e5854e1683f57dbde2d857289095db75084496', class: "video-container" }, index.h("video", { key: 'e44fbc4c020317899620e8aa9e7e3c854ca5a2d9', ref: el => this.videoRef = el, autoplay: true, muted: true, playsinline: true, class: this.shouldMirrorVideo ? 'mirror' : '', style: { display: captureState.isVideoActive ? 'block' : 'none' } }), index.h("div", { key: '2b3af557f8ccb39fd7dbcef07fa6d41d021fd772', ref: el => this.detectionContainer = el, class: `detection-overlay ${this.shouldMirrorVideo ? 'mirror' : ''}` }, this.debug && this.detectionBoxes.map((box, index$1) => (index.h("div", { key: index$1, class: "detection-box", style: {
|
|
19702
19794
|
position: 'absolute',
|
|
19703
19795
|
left: `${box.x}px`,
|
|
19704
19796
|
top: `${box.y}px`,
|
|
@@ -19707,9 +19799,9 @@ const JaakStamps = class {
|
|
|
19707
19799
|
border: '2px solid #32406C',
|
|
19708
19800
|
pointerEvents: 'none',
|
|
19709
19801
|
boxSizing: 'border-box'
|
|
19710
|
-
} })))), this.isMaskReady && (index.h("div", { key: '
|
|
19802
|
+
} })))), this.isMaskReady && (index.h("div", { key: '2cf20cef5e5dc4d5d3282413dce2af0f75b1babe', class: "overlay-mask" }, index.h("div", { key: '241879ebba739d63a736eca258b735c5c8fdac00', class: "card-outline" }, index.h("div", { key: '30d895b1a438636d9cd9a759b0fc096446e256a1', class: "side side-top" }), index.h("div", { key: 'dcca6a422e4c1c20bfc1bd17d7f45305422386a8', class: "side side-right" }), index.h("div", { key: '2cec938bd863737ae9c0906ed0bce2f16b7461fa', class: "side side-bottom" }), index.h("div", { key: 'c6045def438350be85f4333b9166111a9820c8fd', class: "side side-left" })), !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (index.h("div", { key: '187bb5013fe6e7454bfc498b3f24844bb16881a3', class: `guide-text ${this.showPerformanceMessage ? 'performance-warning-text' : ''}` }, this.getGuideText(captureState.step))), captureState.step === 'back' && !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (index.h("div", { key: 'a8ffba382875432493eb6564e4d8872d5d7e485a', class: "back-capture-section" }, index.h("div", { key: '562c149a1f81b8a73df631c81dc2119c1b9427cd', class: "back-capture-buttons" }, (!this.useDocumentDetector || this.performanceDegradedMode || this.showManualCaptureButton) && (index.h("button", { key: '6dc9a222959df902caec68d72c885fba11e41a79', class: "capture-button primary-button", onClick: () => this.takeManualScreenshot(), type: "button", disabled: this.processingButton !== null }, this.processingButton === 'capture-back' && (index.h("span", { key: 'dd3ae6cdba5f4e6085d4d31abebda12f1c1367f8', class: "button-spinner" })), "Capturar Reverso")), index.h("button", { key: 'cddd1951d4370da5165bf0fa450e3c176ec6cf61', class: "skip-button", onClick: () => this.skipBackCapture(), type: "button", disabled: this.processingButton !== null }, this.processingButton === 'skip-back' && (index.h("span", { key: 'da8c1c0af97e164150110cce97d4f4d83e9ffb20', class: "button-spinner" })), this.enableBackDocumentTimer && this.backDocumentTimerRemaining > 0
|
|
19711
19803
|
? `Saltar reverso (${this.backDocumentTimerRemaining}s)`
|
|
19712
|
-
: 'Saltar reverso')))), captureState.isVideoActive && (index.h("div", { key: '
|
|
19804
|
+
: 'Saltar reverso')))), captureState.isVideoActive && (index.h("div", { key: 'd6478c7161d61e1f9f95a9d7bd13cd0cde157061', class: "camera-controls" }, index.h("button", { key: 'dfede9b72f07c88fc5133d3951ddfb6e507b8e8a', class: `camera-selector-button ${this.isSwitchingCamera ? 'loading' : ''}`, onClick: () => this.toggleCameraSelector(), type: "button", title: "Seleccionar c\u00E1mara", disabled: this.isSwitchingCamera }, this.isSwitchingCamera ? (index.h("div", { class: "button-spinner" })) : ('Cámaras')))), this.showCameraSelector && cameraInfo.availableCameras.length > 0 && (index.h("div", { key: '9218f824cc57b7a8b08f87ed0728c3995fa8b57e', class: "camera-selector-dropdown" }, index.h("div", { key: '48828e7532f49c3e9eece8051585aa803ea3c69e', class: "camera-selector-header" }, index.h("span", { key: '49488cbea9f196788e4110cb9b1f132b8097a771' }, "Seleccionar C\u00E1mara"), index.h("button", { key: '5b762a2da1719c645a490e5234703ba07c50d294', class: "close-selector", onClick: () => this.toggleCameraSelector(), type: "button" }, "\u00D7")), index.h("div", { key: '4c13d185e4166dc59621dd8a79a2e7123d810dff', class: "camera-list" }, cameraInfo.availableCameras.map((camera) => (index.h("button", { key: camera.id, class: `camera-option ${cameraInfo.selectedCameraId === camera.id ? 'selected' : ''}`, onClick: () => this.handleCameraSwitch(camera.id), type: "button" }, index.h("span", { class: "camera-label" }, camera.label || `Cámara ${cameraInfo.availableCameras.indexOf(camera) + 1}`, camera.hasAutofocus && (index.h("span", { class: "autofocus-icon", title: "Autofoco disponible" }, "\u29BF"))), cameraInfo.selectedCameraId === camera.id && (index.h("span", { class: "selected-indicator" }, "\u2713")))))), index.h("div", { key: '6860e0fbc0578a74fcd59b3567dd6e4f9a5a4139', class: "device-info" }, index.h("small", { key: '45e6045c7fdc0f4d58bc3c4da059a6b7c2ce09f6' }, "Dispositivo: ", cameraInfo.deviceType)))), this.showManualCaptureButton && captureState.step === 'front' && !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (index.h("div", { key: '600d4932b6a7ae7529ef9dc8c22bb352e0f3ae5d', class: "manual-capture-section" }, index.h("button", { key: '6ad22fbe065602d9214530c374aed05d728114cc', class: "manual-capture-button", onClick: () => this.takeManualScreenshot(), type: "button", disabled: this.processingButton !== null }, this.processingButton === 'capture-front' && (index.h("span", { key: 'd54d5624764ef2774bac1f77551d4c657f4b3e92', class: "button-spinner" })), "Capturar Frente"))))), captureState.isCapturing && (index.h("div", { key: 'ab8c46dd497c3911e72d685310c4dccd0e5aca57', class: "capture-animation" })), captureState.showFlipAnimation && (index.h("div", { key: '545fc8d38085825921e5d61e9d20960b5767a50a', class: "flip-animation" }, index.h("div", { key: 'fd8540ca1e388070233e366aef791e00c1970de1', class: "id-card-icon" }), index.h("div", { key: 'f952bdf0b5eccffe5d6b36930250e699ebfb8fd8', class: "flip-text" }, "\u00A1Voltea tu identificaci\u00F3n!"))), captureState.showSuccessAnimation && (index.h("div", { key: 'cd9b11e3de2f799096b610582b66e044eda64c2e', class: "success-animation" }, index.h("div", { key: '73091c9dae5e6c0f2dbd23bf2e0b760f2495f33b', class: "check-icon" }), index.h("div", { key: 'ad2f9b0b90190b385740bb2fd4ed9454858f13a2', class: "success-text" }, "\u00A1Proceso completado!"))), index.h("div", { key: 'd74d66f12fab510f0aff01f0e233482ed6f63e46', class: `component-status status-${this.currentStatus.type}` }, (this.currentStatus.type === 'loading' || this.currentStatus.type === 'initializing') && (index.h("div", { key: '9060ae79961c7b1b473d5148493fda6462e50388', class: "status-spinner" })), index.h("div", { key: 'fd0c61e49a751afd826d30ed9f63b96b58c8e275', class: "status-content" }, index.h("div", { key: 'd0f0e155fba7a09658f7c21beae5f07c26c0701e', class: "status-message" }, this.currentStatus.message), this.currentStatus.description && (index.h("div", { key: '0694da4ec0ef14750097e69e8caf1db88cf58ed5', class: "status-description" }, this.currentStatus.description)))), this.debug && (index.h("div", { key: '277369112303b12a3cef89c1b7218fdc6f130723', class: "performance-monitor" }, index.h("div", { key: 'f6456cfd210c0d4b8b02b2b73d2405fa7c12923d', class: "performance-expanded" }, index.h("div", { key: '2cd33cbccf2cf3422f09bd3b914a3bc37b0a1190', class: "metrics-row" }, index.h("div", { key: '7871e7fe4f63249731ff33f87023351d9c5ded77', class: "metric-compact" }, index.h("span", { key: 'b864eb43b44838fd5c67c8e430bfa04553130473', class: "metric-label" }, "FPS"), index.h("span", { key: '7a0e6f4ebcf80b1483102094e0906b2b1a5aa83b', class: `metric-value ${this.performanceData.fps < 15 ? 'warning' : this.performanceData.fps < 10 ? 'danger' : 'good'}` }, this.performanceData.fps)), index.h("div", { key: 'ef5e590957e12bd6e9371710654278396baa5314', class: "metric-compact" }, index.h("span", { key: '5cc740e4a2a1e07eb53bcb0cc8c5c3df59f27730', class: "metric-label" }, "MEM"), index.h("span", { key: '758018f1731d7f26aa5d84e7563b059f352be361', class: `metric-value ${this.performanceData.memoryUsage > 100 ? 'warning' : this.performanceData.memoryUsage > 200 ? 'danger' : 'good'}` }, this.performanceData.memoryUsage, "MB"))), index.h("div", { key: '1bedd37486ae4b8ba547507f2664ea19c67a18c7', class: "metrics-row" }, index.h("div", { key: '4f99be14cda01b199cae93905043a6e03a852d1b', class: "metric-compact" }, index.h("span", { key: 'c29a4a3461633e776cd86168c59c89c6b39af18d', class: "metric-label" }, "INF"), index.h("span", { key: '9401828ffd1d3e41ce473ba3d0aec592a683472f', class: `metric-value ${this.performanceData.inferenceTime > 100 ? 'warning' : this.performanceData.inferenceTime > 200 ? 'danger' : 'good'}` }, this.performanceData.inferenceTime, "ms")), index.h("div", { key: '7d4fdad150bb665640add08464ea361aeaa8ef6b', class: "metric-compact" }, index.h("span", { key: '7c21d775970466b339fdbb392227ec7006b87e31', class: "metric-label" }, "FRAME"), index.h("span", { key: '255d408312a11f350ea75654fc64edf0d4bcfef2', class: `metric-value ${this.performanceData.frameProcessingTime > 50 ? 'warning' : this.performanceData.frameProcessingTime > 100 ? 'danger' : 'good'}` }, this.performanceData.frameProcessingTime, "ms"))), index.h("div", { key: '54ab129c3ffda4f1a32a2b0f437a7c38cb480aba', class: "metrics-row" }, index.h("div", { key: 'a246db2ef3a69d0d64827a73dd32968cb1e978e9', class: "metric-compact" }, index.h("span", { key: '8da1c9a5be45bcc23584234cb04f0e75fa3662c6', class: "metric-label" }, "DET"), index.h("span", { key: 'ad05c2b885a6b344391f70ce3acee8b41523743d', class: "metric-value good" }, this.performanceData.successfulDetections, "/", this.performanceData.totalDetections)), index.h("div", { key: '7449e8f7cbd15a6b828b90c923212c3578de3d11', class: "metric-compact" }, index.h("span", { key: 'da37f89e9641edfdfd60de7fdbf2f6285a2a4120', class: "metric-label" }, "RATE"), index.h("span", { key: 'de71b2072ce451a304ceb6b158d32b0ecde6d64a', class: `metric-value ${this.performanceData.detectionRate < 30 ? 'danger' : this.performanceData.detectionRate < 60 ? 'warning' : 'good'}` }, this.performanceData.detectionRate, "%")))))), index.h("div", { key: '6e2c10e239bca24062cd2972b5e4a3eb0951d0eb', class: "watermark" }, index.h("img", { key: '63fbe0ade07a191ccc9c007fc2813ac8f6e5ab2f', src: "https://storage.googleapis.com/jaak-static/commons/powered-by-jaak.png", alt: "Powered by Jaak" }))))));
|
|
19713
19805
|
}
|
|
19714
19806
|
// Utility methods
|
|
19715
19807
|
updateDetectionBoxes(boxes) {
|
|
@@ -20432,28 +20524,35 @@ const JaakStamps = class {
|
|
|
20432
20524
|
}
|
|
20433
20525
|
// Adaptive frame skipping based on performance
|
|
20434
20526
|
getAdaptiveFrameSkip() {
|
|
20527
|
+
// Check if running on mobile device for more aggressive frame skipping
|
|
20528
|
+
const isMobileDevice = this.cameraInfoWithAutofocus.deviceType === 'mobile' ||
|
|
20529
|
+
/Android|iPhone|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
|
|
20530
|
+
const isTablet = this.cameraInfoWithAutofocus.deviceType === 'tablet' ||
|
|
20531
|
+
(/iPad|Android/i.test(navigator.userAgent) && window.innerWidth >= 768);
|
|
20532
|
+
// Mobile-specific base frame skip (more aggressive to prevent slow motion effect)
|
|
20533
|
+
const mobileBaseSkip = isMobileDevice && !isTablet ? 4 : this.BASE_FRAME_SKIP;
|
|
20435
20534
|
// Base conditions for high frame skip
|
|
20436
20535
|
if (this.consecutiveFailures > 20)
|
|
20437
20536
|
return this.MAX_FRAME_SKIP;
|
|
20438
20537
|
if (this.performanceMetrics.inferenceTime > 200)
|
|
20439
|
-
return 6;
|
|
20538
|
+
return Math.max(6, mobileBaseSkip);
|
|
20440
20539
|
if (this.performanceMetrics.memoryUsage > 200)
|
|
20441
|
-
return 5;
|
|
20540
|
+
return Math.max(5, mobileBaseSkip);
|
|
20442
20541
|
// Calculate average processing time
|
|
20443
20542
|
if (this.performanceHistory.length > 0) {
|
|
20444
20543
|
const avgProcessingTime = this.performanceHistory.reduce((a, b) => a + b, 0) / this.performanceHistory.length;
|
|
20445
20544
|
if (avgProcessingTime > 100)
|
|
20446
|
-
return 4;
|
|
20545
|
+
return Math.max(4, mobileBaseSkip);
|
|
20447
20546
|
if (avgProcessingTime > 80)
|
|
20448
|
-
return 3;
|
|
20547
|
+
return Math.max(3, mobileBaseSkip);
|
|
20449
20548
|
if (avgProcessingTime > 60)
|
|
20450
|
-
return this.BASE_FRAME_SKIP + 1;
|
|
20549
|
+
return Math.max(this.BASE_FRAME_SKIP + 1, mobileBaseSkip);
|
|
20451
20550
|
}
|
|
20452
20551
|
// Low memory devices get higher frame skip
|
|
20453
20552
|
if (this.performanceMetrics.memoryUsage > 150)
|
|
20454
|
-
return 4;
|
|
20455
|
-
//
|
|
20456
|
-
return
|
|
20553
|
+
return Math.max(4, mobileBaseSkip);
|
|
20554
|
+
// Mobile devices use higher base frame skip for smoother video
|
|
20555
|
+
return mobileBaseSkip;
|
|
20457
20556
|
}
|
|
20458
20557
|
// Método para resetear la máscara a color blanco
|
|
20459
20558
|
resetMaskToWhite() {
|