Skip to main content

FrameSource Interface

All frame sources implement this interface:
interface FrameSource {
  onFrame: ((frame: Frame) => void) | null;
  start(): Promise<void>;
  stop(): Promise<void>;
}

type Frame = {
  data: Uint8ClampedArray | number[];  // RGBA pixel data
  width: number;
  height: number;
  roi?: ROI;
  rois?: ROI[];
  timestampMs?: number;
};

type ROI = { x: number; y: number; w: number; h: number };

MediaPipeFrameSource

Captures camera frames and uses MediaPipe for face detection, providing a face ROI with each frame:
import { MediaPipeFrameSource } from "@elata-biosciences/rppg-web";

const source = new MediaPipeFrameSource();

source.onFrame = (frame) => {
  // frame.roi contains the detected face bounding box
  // frame.data contains the camera image pixels
  console.log("Face ROI:", frame.roi);
};

await source.start();
// ... later
await source.stop();

MediaPipeFaceFrameSource

A more specialized variant that uses MediaPipe FaceMesh for precise facial landmark detection. Provides multiple ROIs for forehead, cheeks, etc.:
import { MediaPipeFaceFrameSource, loadFaceMesh } from "@elata-biosciences/rppg-web";

const faceMesh = await loadFaceMesh();
const source = new MediaPipeFaceFrameSource(faceMesh);

source.onFrame = (frame) => {
  // frame.rois may contain multiple face regions
  console.log("Face regions:", frame.rois?.length);
};

await source.start();

loadFaceMesh

Helper to load the MediaPipe FaceMesh model:
import { loadFaceMesh } from "@elata-biosciences/rppg-web";

const faceMesh = await loadFaceMesh();

DemoRunner

DemoRunner orchestrates a frame source and RppgProcessor together, handling ROI extraction, skin masking, and stats reporting:
import { DemoRunner, MediaPipeFrameSource, RppgProcessor } from "@elata-biosciences/rppg-web";
import type { DemoRunnerOptions } from "@elata-biosciences/rppg-web";

const source = new MediaPipeFrameSource();
const processor = new RppgProcessor("wasm", 30);

const options: DemoRunnerOptions = {
  useSkinMask: true,
  onStats: (stats) => {
    console.log(`Green: ${stats.intensity}, Skin: ${stats.skinRatio}, FPS: ${stats.fps}`);
  },
};

const runner = new DemoRunner(source, processor, options);
await runner.start();

// ... later
await runner.stop();

DemoRunnerOptions

OptionTypeDefaultDescription
roiROI | nullnullFixed ROI override (null = use face detection)
sampleRatenumberOverride sample rate
roiSmoothingAlphanumberExponential smoothing for ROI jitter
useSkinMaskbooleanfalseApply YCbCr skin tone mask
skinRatioSmoothingAlphanumberSmooth the skin ratio metric
onStatsfunctionCallback with per-frame statistics

ROI Helper

Extract average green channel intensity from a region of interest:
import { averageGreenInROI } from "@elata-biosciences/rppg-web";

const intensity = averageGreenInROI(frame, roi.x, roi.y, roi.w, roi.h);