Model Loading Progress
INFO
Note: Model Loading Progress tracking is currently available for web SDKs (JavaScript, React, Vue). This feature provides real-time visibility into the AI model loading process, including download and caching stages.
When the Vitals™ SDK initializes for the first time, it downloads and loads various AI models (such as face detection models, facial landmark models, and real-time estimators) from the content delivery network (CDN). Depending on network conditions and device performance, this initialization process can take several seconds. The Model Loading Progress feature enables you to track this process and provide meaningful feedback to your users.
Overview
The Vitals™ SDK uses multiple AI modules working together to provide accurate vital sign measurements. During initialization, the SDK loads several model files from different modules:
AI Modules
The SDK loads the following AI modules:
- Face Detection Module (
face-mesh/mp-vision-face-mesh): Detects and tracks face landmarks with 468+ points - Age Estimation Module (
face-api): Estimates user age for more accurate vital sign calculations - Face API Models: Additional models for facial analysis including gender detection and facial landmark detection
Each module consists of multiple model files that are downloaded and loaded during initialization. For example:
- The face-api module loads:
ssd_mobilenetv1_model,age_gender_model,face_landmark_68_model - The face-mesh module loads:
face_landmarker.task, WASM runtime files - Each module may have 3-5+ model files totaling several megabytes
Loading Stages
Each model file progresses through the following stages:
- Downloading: Model file is being fetched from the CDN to the user's device
- Caching: Downloaded model is being saved to browser cache for faster subsequent loads
- Ready: All model files from all modules are fully loaded and initialized, ready for scanning
The overall progress percentage aggregates the loading state across all modules and all files within those modules.
Key Components
The model loading feature consists of two main components:
| Component | Purpose |
|---|---|
| Built-in Visualization | Optional overlay that automatically displays model loading progress on top of the video element |
| Progress Callback | Manual callback handler for custom UI implementations or monitoring |
You can use either component independently or combine them based on your needs.
Key Benefits
| Benefit | Description |
|---|---|
| User Feedback | Show loading bars or status text so users know the app is initializing |
| Network Monitoring | Understand actual model loading times across different devices and networks |
| Custom UI | Implement custom loading overlays matching your app's design |
| Module-Specific Feedback | Display different messages for face detection vs. age estimation loading |
| Error Handling | Detect and respond to download failures or timeout scenarios |
| Performance Insights | Monitor which models/modules take the longest to load |
Implementation Approaches
The web SDKs provide two main mechanisms to handle model loading progress:
1. Built-in Visualization (Easiest)
Enable an automatic overlay that displays loading progress without writing code:
import { createVitalSignCamera } from 'ts-vital-sign-camera';
const video = document.querySelector('video')!;
const camera = createVitalSignCamera({
isActive: true,
userInfo: { age: 30, gender: 'male' }
});
camera.bind(video);
// Enable default model loading progress visualization
camera.visualizationOptions = {
modelLoadingProgress: {
enabled: true // Shows default loading overlay
}
};import { VitalSignCamera, Gender } from 'react-vital-sign-camera';
export function CameraComponent() {
return (
<VitalSignCamera
isActive={true}
userInfo={{ age: 30, gender: Gender.Male }}
visualizationOptions={{
modelLoadingProgress: {
enabled: true
}
}}
/>
);
}<script setup lang="ts">
import { VitalSignCamera, Gender } from 'vue-vital-sign-camera'
</script>
<template>
<div>
<VitalSignCamera
:is-active="true"
:user-info="{ age: 30, gender: Gender.Male }"
:visualization-options="{
modelLoadingProgress: {
enabled: true
}
}"
/>
</div>
</template>2. Manual Callback (Most Flexible)
Handle loading progress programmatically for custom UI:
import { createVitalSignCamera } from 'ts-vital-sign-camera';
import type { ModelLoadingProgressEvent } from 'ts-vital-sign-camera';
const video = document.querySelector('video')!;
const camera = createVitalSignCamera({
isActive: true,
userInfo: { age: 30, gender: 'male' },
// Pass callback during creation (recommended approach)
onModelLoadingProgress: (progress: ModelLoadingProgressEvent) => {
console.log(`Loading: ${progress.percentage}%`);
console.log(`Stage: ${progress.stage.type}`);
// Update custom UI
const progressBar = document.getElementById('loading-progress');
if (progressBar) {
progressBar.style.width = `${progress.percentage}%`;
}
}
});
camera.bind(video);import { VitalSignCamera, Gender } from 'react-vital-sign-camera';
import { useState } from 'react';
import type { ModelLoadingProgressEvent } from 'react-vital-sign-camera';
export function CameraWithProgress() {
const [progress, setProgress] = useState<ModelLoadingProgressEvent | null>(null);
return (
<>
{progress && (
<div>
Loading: {progress.percentage}%
{progress.stage.type === 'downloading' && (
<span> ({Math.round(progress.loaded / 1024 / 1024)}MB / {Math.round(progress.total / 1024 / 1024)}MB)</span>
)}
</div>
)}
<VitalSignCamera
isActive={true}
userInfo={{ age: 30, gender: Gender.Male }}
onModelLoadingProgress={setProgress}
/>
</>
);
}<script setup lang="ts">
import { ref } from 'vue'
import { VitalSignCamera, Gender } from 'vue-vital-sign-camera'
import type { ModelLoadingProgressEvent } from 'vue-vital-sign-camera'
const progress = ref<ModelLoadingProgressEvent | null>(null)
const handleModelLoadingProgress = (event: ModelLoadingProgressEvent) => {
progress.value = event
}
</script>
<template>
<div>
<div v-if="progress">
Loading: {{ progress.percentage }}%
<span v-if="progress.stage.type === 'downloading'">
({{ Math.round(progress.loaded / 1024 / 1024) }}MB / {{ Math.round(progress.total / 1024 / 1024) }}MB)
</span>
</div>
<VitalSignCamera
:is-active="true"
:user-info="{ age: 30, gender: Gender.Male }"
@onModelLoadingProgress="handleModelLoadingProgress"
/>
</div>
</template>Progress Event Structure
The ModelLoadingProgressEvent provides detailed information about the current loading status across all AI modules:
interface ModelLoadingProgressEvent {
/** Current progress percentage (0-100) */
percentage: number;
/** Bytes downloaded so far for the module that emitted this event (downloading stage) */
loaded: number;
/** Total bytes to download for that module (downloading stage) */
total: number;
/** Current stage with detailed information */
stage: {
type: 'downloading' | 'caching' | 'ready';
fromCache: boolean; // Whether model was loaded from cache
filename?: string; // Name of the specific file being processed
error?: Error; // Error object if loading failed
};
/** Name of the module being loaded (e.g., 'face-mesh', 'face-api', 'mp-vision-face-mesh') */
module?: string;
}How the Percentage Is Calculated
- Events come from individual modules (face detection, age estimation, etc.); there is no cross-module aggregation.
- Downloading stage (emitted by
ModelFetchInterceptor): starts at ~30% and rises toward 100% based on bytes (or file-count fallback) for that module only. - Caching stage: 0–100% for the specific file being cached; values can drop relative to the previous downloading percentage.
- Ready stage: always 100% for the emitting module and means downloads are finished for that module; it does not mean the camera is initialized—wait for
onInitialized. - Modules may emit their own early progress values (e.g., a 10% kickoff event) before downloads begin.
Understanding the Module Property
The module property identifies which AI component is currently loading:
'face-api': Age estimation and facial analysis models'mp-vision-face-mesh': MediaPipe face detection and landmark models'face-mesh': Alternative face detection implementation
You can use this to show more specific loading messages:
onModelLoadingProgress: (progress) => {
let message = 'Loading AI models...';
if (progress.module) {
if (progress.module.includes('face-api') || progress.module.includes('age')) {
message = 'Loading age estimation models...';
} else if (progress.module.includes('face') || progress.module.includes('mesh')) {
message = 'Loading face detection models...';
}
}
console.log(message, `${progress.percentage}%`);
}const getLoadingMessage = (progress: ModelLoadingProgressEvent) => {
if (!progress.module) return 'Loading AI models...';
if (progress.module.includes('face-api') || progress.module.includes('age')) {
return 'Loading age estimation models...';
} else if (progress.module.includes('face') || progress.module.includes('mesh')) {
return 'Loading face detection models...';
}
return 'Loading AI models...';
};const getLoadingMessage = (progress: ModelLoadingProgressEvent) => {
if (!progress.module) return 'Loading AI models...';
if (progress.module.includes('face-api') || progress.module.includes('age')) {
return 'Loading age estimation models...';
} else if (progress.module.includes('face') || progress.module.includes('mesh')) {
return 'Loading face detection models...';
}
return 'Loading AI models...';
};Stage Types
- downloading: Model file for that module is being downloaded from the CDN (the
filenameproperty shows which specific file) - caching: Model file for that module is being saved to browser cache for future use
- ready: The emitting module has finished downloading (or fetched from cache) all of its model files; camera warm-up and
onInitializedmay still be pending
Multiple Files Per Module
Progress events are fired for each individual file within each module. For example, the face-api module may emit events for ssd_mobilenetv1_model-weights_manifest.json, age_gender_model-shard1, and other files sequentially. The percentage reflects progress for the emitting module across its files (not a cross-module aggregate).
Target SDK
TIP
You can refer to the sample code and the API Reference for more details. Most related API(s) include: VitalSignCameraInterface.onModelLoadingProgress, ModelLoadingProgressEvent, and VisualizationOptions.modelLoadingProgress.
The JavaScript SDK provides two ways to handle model loading progress: a built-in visualization overlay and a callback handler for custom implementations.
Using Built-in Visualization
The simplest approach is to enable the default model loading progress overlay:
import { createVitalSignCamera } from 'ts-vital-sign-camera';
window.onload = () => {
const video = document.querySelector('video')!;
const camera = createVitalSignCamera({
isActive: true,
userInfo: { age: 30, gender: 'male' }
});
camera.bind(video);
// Enable default loading progress visualization
camera.visualizationOptions = {
modelLoadingProgress: {
enabled: true
}
};
};import { createVitalSignCamera } from 'ts-vital-sign-camera';
window.onload = () => {
const video = document.querySelector('video');
const camera = createVitalSignCamera({
isActive: true,
userInfo: { age: 30, gender: 'male' }
});
camera.bind(video);
// Enable default loading progress visualization
camera.visualizationOptions = {
modelLoadingProgress: {
enabled: true
}
};
};The built-in overlay automatically displays:
- A progress bar showing percentage complete
- Current loading stage text (downloading/caching/ready)
- Bytes loaded and total bytes (can be disabled with
showBytes: false)
Using Progress Callback
For custom UI implementations, pass the onModelLoadingProgress callback during camera creation:
Important
The loading overlay should remain visible until the onInitialized callback is fired, not just when the progress reaches the 'ready' stage. The 'ready' stage indicates that models are loaded, but onInitialized confirms the camera is fully initialized and ready for use.
const video = document.querySelector('video')!;
let isLoading = true;
let progress = null;
const overlayEl = document.getElementById('loading-container');
const barEl = document.getElementById('loading-progress');
const textEl = document.getElementById('loading-text');
const camera = createVitalSignCamera({
isActive: true,
userInfo: { age: 30, gender: 'male' },
onModelLoadingProgress: (evt) => {
progress = evt;
if (barEl) barEl.style.width = `${evt.percentage}%`;
if (textEl) textEl.textContent = evt.stage.type === 'ready' ? 'Initializing...' : `${evt.percentage}%`;
if (overlayEl) overlayEl.style.display = 'flex'; // ensure visible even for cached loads
},
onInitialized: () => {
isLoading = false;
if (overlayEl) overlayEl.style.display = 'none';
}
});
camera.bind(video);Recommended Overlay Strategy (JS)
- Start with the overlay visible (
display: flex); cached loads can still need a quick state. - Update width/text in
onModelLoadingProgress; whenstage.type === 'ready', show “Initializing...”. - Dismiss only in
onInitialized. - Provide fallback text when
progressis null (before first event).
Customizing Built-in Visualization
The default overlay can be customized with colors and display options:
const video = document.querySelector('video')!;
const camera = createVitalSignCamera({
isActive: true,
userInfo: { age: 30, gender: 'male' }
});
camera.bind(video);
// Customize the built-in visualization
camera.visualizationOptions = {
modelLoadingProgress: {
enabled: true,
backgroundColor: 'rgba(0, 0, 0, 0.7)', // Overlay background
progressColor: '#4CAF50', // Progress bar color
textColor: '#4CAF50', // Text color
showBytes: true // Show MB / MB
}
};Complete Example with Custom UI
Here's a more complete example showing both the callback and custom HTML:
<!DOCTYPE html>
<html>
<head>
<style>
#loading-container {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.7);
display: none;
align-items: center;
justify-content: center;
z-index: 1000;
}
.loading-content {
background: white;
padding: 40px;
border-radius: 8px;
max-width: 400px;
text-align: center;
}
.progress-bar-container {
width: 100%;
height: 8px;
background: #e0e0e0;
border-radius: 4px;
margin: 20px 0;
overflow: hidden;
}
.progress-bar-fill {
height: 100%;
background: #4CAF50;
width: 0%;
transition: width 0.3s ease;
}
</style>
</head>
<body>
<div id="loading-container">
<div class="loading-content">
<h2>Loading AI Models</h2>
<div class="progress-bar-container">
<div class="progress-bar-fill" id="progress-fill"></div>
</div>
<p id="progress-text">Initializing...</p>
</div>
</div>
<video id="video" style="display: none;"></video>
<script type="module">
import { createVitalSignCamera } from 'ts-vital-sign-camera';
window.onload = async () => {
const video = document.querySelector('video');
const loadingContainer = document.getElementById('loading-container');
// Show loading container
loadingContainer.style.display = 'flex';
const camera = createVitalSignCamera({
isActive: true,
userInfo: { age: 30, gender: 'male' },
// Handle progress updates via callback
onModelLoadingProgress: (progress) => {
const progressFill = document.getElementById('progress-fill');
const progressText = document.getElementById('progress-text');
if (progressFill) {
progressFill.style.width = `${progress.percentage}%`;
}
// Format size info
const sizeMB = (progress.total / 1024 / 1024).toFixed(1);
const loadedMB = (progress.loaded / 1024 / 1024).toFixed(1);
if (progressText) {
if (progress.stage.type === 'downloading') {
progressText.textContent =
`Downloading models: ${loadedMB}MB / ${sizeMB}MB (${progress.percentage}%)`;
} else if (progress.stage.type === 'caching') {
progressText.textContent = `Caching models: ${progress.percentage}%`;
} else if (progress.stage.type === 'ready') {
progressText.textContent = 'Initializing...';
}
}
},
// Hide loading overlay when fully initialized
onInitialized: () => {
console.log('Camera initialized and ready');
setTimeout(() => {
loadingContainer.style.display = 'none';
}, 300);
}
});
camera.bind(video);
};
</script>
</body>
</html>Understanding Progress Events
The progress callback receives a ModelLoadingProgressEvent with the following properties:
| Property | Type | Description |
|---|---|---|
percentage | number | Progress from 0-100 |
loaded | number | Bytes downloaded |
total | number | Total bytes to download |
stage.type | string | One of: 'downloading', 'caching', 'ready' |
stage.fromCache | boolean | True if model came from browser cache |
stage.filename | string | Name of the file being processed |
stage.error | Error | Error object if loading failed |
module | string | Name of the module being loaded |
Error Handling
The callback will still be invoked if an error occurs during loading:
const video = document.querySelector('video')!;
const camera = createVitalSignCamera({
isActive: true,
userInfo: { age: 30, gender: 'male' }
});
camera.bind(video);
// Set error handling after camera creation
camera.onModelLoadingProgress = (progress) => {
if (progress.stage.error) {
console.error('Model loading failed:', progress.stage.error.message);
// Show error message to user
const errorDiv = document.getElementById('error-message');
if (errorDiv) {
errorDiv.textContent = 'Failed to load AI models. Please refresh the page.';
errorDiv.style.display = 'block';
}
} else {
// Normal progress update
console.log(`${progress.percentage}% complete`);
}
};Combining Both Approaches
You can use both the built-in visualization and a callback for monitoring:
const video = document.querySelector('video')!;
const camera = createVitalSignCamera({
isActive: true,
userInfo: { age: 30, gender: 'male' },
// Set callback for custom monitoring and analytics
onModelLoadingProgress: (progress) => {
// Send analytics, log progress, etc.
console.log('Model loading progress:', progress);
},
// Track when initialization completes
onInitialized: () => {
console.log('Camera ready for scanning');
}
});
camera.bind(video);
// Enable built-in visualization after binding
camera.visualizationOptions = {
modelLoadingProgress: {
enabled: true
}
};Performance Tips
- Throttle updates: The callback may fire many times per second. Only update the DOM at intervals
- Cache DOM references: Store element references instead of querying each time
- Use CSS transitions: Let CSS handle smooth progress bar animations
- Avoid layout thrashing: Batch DOM reads and writes
Important Notes
- The callback may be called rapidly during downloads. Consider throttling UI updates
- On subsequent app loads, models will load from browser cache, making the process very fast
- The
fromCacheproperty indicates whether the current file came from cache - Each module (face detection, landmarks, estimators) may report separate progress
Recommended Overlay Strategy
Use this pattern to ensure the overlay stays up for both cold and warm loads:
- Start with
isLoading = trueso cached models still show overlay briefly. - Update progress in
onModelLoadingProgress. - Dismiss overlay only in
onInitialized(not at stageready). - Keep a graceful message when
progressis null (before first event).
let isLoading = true;
let progress = null;
const loadingEl = document.getElementById('loading-overlay');
const barEl = document.getElementById('loading-bar');
const textEl = document.getElementById('loading-text');
const camera = createVitalSignCamera({
isActive: true,
userInfo: { age: 30, gender: 'male' },
onModelLoadingProgress: (evt) => {
progress = evt;
if (barEl) barEl.style.width = `${evt.percentage}%`;
if (textEl) textEl.textContent = evt.stage.type === 'ready' ? 'Initializing...' : `${evt.percentage}%`;
},
onInitialized: () => {
isLoading = false;
if (loadingEl) loadingEl.style.display = 'none';
}
});
camera.bind(document.querySelector('video'));import { useState, useCallback } from 'react';
import { VitalSignCamera, Gender } from 'react-vital-sign-camera';
import type { ModelLoadingProgressEvent } from 'react-vital-sign-camera';
export function CameraWithOverlay() {
const [isLoading, setIsLoading] = useState(true);
const [progress, setProgress] = useState<ModelLoadingProgressEvent | null>(null);
const handleProgress = useCallback((evt: ModelLoadingProgressEvent) => {
setProgress(evt);
}, []);
const handleInitialized = useCallback(() => {
setIsLoading(false);
}, []);
return (
<>
{isLoading && (
<div className="overlay">
<div className="bar" style={{ width: `${progress?.percentage || 0}%` }} />
<div className="text">
{progress?.stage.type === 'ready' ? 'Initializing...' : `${progress?.percentage || 0}%`}
</div>
</div>
)}
<VitalSignCamera
isActive={true}
userInfo={{ age: 30, gender: Gender.Male }}
onModelLoadingProgress={handleProgress}
onInitialized={handleInitialized}
/>
</>
);
}<script setup lang="ts">
import { ref } from 'vue'
import { VitalSignCamera, Gender } from 'vue-vital-sign-camera'
import type { ModelLoadingProgressEvent } from 'vue-vital-sign-camera'
const isLoading = ref(true)
const progress = ref<ModelLoadingProgressEvent | null>(null)
const handleProgress = (evt: ModelLoadingProgressEvent) => {
progress.value = evt
}
const handleInitialized = () => {
isLoading.value = false
}
</script>
<template>
<div>
<div v-if="isLoading" class="overlay">
<div class="bar" :style="{ width: `${progress?.percentage || 0}%` }"></div>
<div class="text">
<span v-if="progress?.stage.type === 'ready'">Initializing...</span>
<span v-else>{{ progress?.percentage || 0 }}%</span>
</div>
</div>
<VitalSignCamera
:is-active="true"
:user-info="{ age: 30, gender: Gender.Male }"
@onModelLoadingProgress="handleProgress"
@onInitialized="handleInitialized"
/>
</div>
</template>Understanding Multi-Module Loading
The SDK loads multiple AI modules in sequence or parallel, with each module containing multiple model files. Progress events are emitted for each file as it progresses through the downloading, caching, and ready stages.
Typical Loading Sequence
Progress events from different modules are interleaved; each module reports its own percentages:
- Face detection module begins downloading
Example:{ percentage: 30, stage: { type: 'downloading', filename: 'face_landmarker.task' }, module: 'mp-vision-face-mesh' } - Age estimation (face-api) starts downloading in parallel
Example:{ percentage: 30, stage: { type: 'downloading', filename: 'ssd_mobilenetv1_model-weights_manifest.json' }, module: 'face-api' } - Face detection finishes downloading its files
Example:{ percentage: 100, stage: { type: 'ready', fromCache: false }, module: 'mp-vision-face-mesh' } - Age estimation finishes downloading its files
Example:{ percentage: 100, stage: { type: 'ready', fromCache: false }, module: 'face-api' }
Because each module reports independently, do not treat the percentages as a single global progress value.
Progress Calculation (per module)
- Downloading stage (ModelFetchInterceptor): Uses a per-module baseline of ~30% plus byte-based progress for that module's downloads (70% range). If content-length is missing, it estimates using file counts. Values are per module, not aggregated.
- Caching stage: Uses
loaded/total × 100for the specific file being cached (values can dip below the previous downloading percentage). - Custom kickoff events: Some modules emit a fixed percentage (e.g.,
10%) before downloads start to show immediate feedback. - Ready stage: Always
100%for the emitting module; the camera may still be warming up. UseonInitializedto know when the camera is fully ready.
Because events are per module, displaying an "overall" bar should use the latest event or combine module-specific bars instead of assuming a single aggregated percentage.
Module-Specific Progress Tracking
To track progress for specific modules, you can filter events by the module property:
const moduleProgress = {
'face-api': 0,
'mp-vision-face-mesh': 0
};
camera = createVitalSignCamera({
isActive: true,
userInfo: { age: 30, gender: 'male' },
onModelLoadingProgress: (progress) => {
// Track module-specific progress
if (progress.module) {
moduleProgress[progress.module] = progress.percentage;
console.log(`${progress.module}: ${progress.percentage}%`);
}
// Display overall progress
console.log(`Overall: ${progress.percentage}%`);
}
});import { useState } from 'react';
function CameraWithModuleTracking() {
const [moduleProgress, setModuleProgress] = useState<Record<string, number>>({});
const [overallProgress, setOverallProgress] = useState(0);
const handleProgress = (progress: ModelLoadingProgressEvent) => {
setOverallProgress(progress.percentage);
if (progress.module) {
setModuleProgress(prev => ({
...prev,
[progress.module!]: progress.percentage
}));
}
};
return (
<div>
<div>Overall: {overallProgress}%</div>
{Object.entries(moduleProgress).map(([module, percent]) => (
<div key={module}>{module}: {percent}%</div>
))}
<VitalSignCamera
isActive={true}
userInfo={{ age: 30, gender: Gender.Male }}
onModelLoadingProgress={handleProgress}
/>
</div>
);
}<script setup lang="ts">
import { ref } from 'vue'
import type { ModelLoadingProgressEvent } from 'vue-vital-sign-camera'
const moduleProgress = ref<Record<string, number>>({})
const overallProgress = ref(0)
const handleProgress = (progress: ModelLoadingProgressEvent) => {
overallProgress.value = progress.percentage
if (progress.module) {
moduleProgress.value[progress.module] = progress.percentage
}
}
</script>
<template>
<div>
<div>Overall: {{ overallProgress }}%</div>
<div v-for="[module, percent] in Object.entries(moduleProgress)" :key="module">
{{ module }}: {{ percent }}%
</div>
<VitalSignCamera
:is-active="true"
:user-info="{ age: 30, gender: Gender.Male }"
@onModelLoadingProgress="handleProgress"
/>
</div>
</template>File-Level Progress Tracking
To track individual file downloads, use the stage.filename property:
onModelLoadingProgress: (progress) => {
if (progress.stage.filename) {
console.log(`Downloading: ${progress.stage.filename}`);
console.log(`Module: ${progress.module || 'unknown'}`);
console.log(`Progress: ${progress.loaded} / ${progress.total} bytes`);
}
}const [currentFile, setCurrentFile] = useState<string>('');
const handleProgress = (progress: ModelLoadingProgressEvent) => {
if (progress.stage.filename) {
setCurrentFile(progress.stage.filename);
}
};
return (
<div>
{currentFile && <div>Loading: {currentFile}</div>}
<VitalSignCamera
isActive={true}
userInfo={{ age: 30, gender: Gender.Male }}
onModelLoadingProgress={handleProgress}
/>
</div>
);<script setup lang="ts">
const currentFile = ref<string>('')
const handleProgress = (progress: ModelLoadingProgressEvent) => {
if (progress.stage.filename) {
currentFile.value = progress.stage.filename
}
}
</script>
<template>
<div>
<div v-if="currentFile">Loading: {{ currentFile }}</div>
<VitalSignCamera
:is-active="true"
:user-info="{ age: 30, gender: Gender.Male }"
@onModelLoadingProgress="handleProgress"
/>
</div>
</template>Best Practices
User Experience
- Show progress indication during initialization
- Display estimated time remaining if available
- Use smooth animations or transitions for progress updates
- Provide clear messaging about what's being loaded
Performance
- Don't update progress display too frequently (throttle to 100-200ms)
- Cache DOM element references instead of querying repeatedly
- Use efficient CSS transitions rather than JavaScript animations
- Consider that progress may complete very quickly if models are cached
Error Handling
- Handle network timeouts gracefully
- Provide options for users to retry if loading fails
- Check
progress.stage.errorfor error information - Log errors for debugging purposes
Testing
- Test with slow network connections using browser DevTools throttling
- Verify behavior on low-end devices
- Test with intermittent network failures
- Check both cold load (first time) and warm load (from cache) scenarios
Related Documentation
- VitalSignCameraInterface API Reference - Camera instance methods and properties
- ModelLoadingProgressEvent Reference - Complete event structure
- Error Handling Guide - How to handle loading errors
- Quick Start Guide - Getting started with the SDK