scripts/config.jsjavascript
/**
* @module config
* @description
* Centralised configuration constants for Ghostmaxxing. Lives in one place so that
* URLs, detector thresholds, and recording defaults can be changed without
* touching engine code. All values here are static and module-load-time
* resolvable; runtime-mutable state belongs in `state.js`.
*
* Why a separate module: keeps testable engines free of hard-coded URLs
* (which makes them mockable) and concentrates the network surface in one
* file so the upgrade path to npm + bundler is mechanical.
*/
/**
* Public CDN URLs for the face-api.js model shards (TinyFaceDetector + the
* landmarks / recognition / age-gender heads). These point at the canonical
* `face-api.js-models` mirror, which serves the same weights for both the
* unmaintained original library and the @vladmandic fork in use here.
*
* @see scripts/main.js – `loadModels()` reads these and calls `faceapi.nets.*.loadFromUri()`.
*/
export const MODEL_URLS = {
tiny: 'https://cdn.jsdelivr.net/gh/justadudewhohacks/face-api.js-models@master/tiny_face_detector',
landmarks: 'https://cdn.jsdelivr.net/gh/justadudewhohacks/face-api.js-models@master/face_landmark_68',
recognition: 'https://cdn.jsdelivr.net/gh/justadudewhohacks/face-api.js-models@master/face_recognition',
ageGender: 'https://cdn.jsdelivr.net/gh/justadudewhohacks/face-api.js-models@master/age_gender_model',
expressions: 'https://cdn.jsdelivr.net/gh/justadudewhohacks/face-api.js-models@master/face_expression'
};
export const ANALYZE_PANEL_MAX_WIDTH_DESKTOP = 900;
/**
* Maximum number of face thumbnails retained in the dedicated localStorage
* thumbnail store. When the limit is exceeded, the oldest thumbnail entry is
* evicted (FIFO by `savedAt`).
*/
export const THUMBNAIL_MAX_ENTRIES = 200;
/**
* Extra margin ratio applied around the detected face box before thumbnail
* cropping. The margin is computed from the shortest side of the box.
*/
export const THUMBNAIL_MARGIN_RATIO = 0.30;
/**
* Output thumbnail size in pixels (square canvas, width and height).
*/
export const THUMBNAIL_OUTPUT_SIZE = 160;
/**
* JPEG quality used when exporting captured face thumbnails.
*/
export const THUMBNAIL_JPEG_QUALITY = 0.8;
/**
* Root CDN URL for the @mediapipe/tasks-vision package. Used as a base for
* dynamic ES-module imports of `FaceLandmarker` and `ImageEmbedder`.
*
* @see scripts/engine-3d.js – `loadMobileNet()` does `await import(MEDIAPIPE_TASKS_VISION_URL)`.
* @see scripts/mediapipe-loop.js – uses the same package for face landmarks.
*/
export const MEDIAPIPE_TASKS_VISION_URL = 'https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@0.10.35';
/**
* URL of the MediaPipe WASM blob loaded by `FilesetResolver.forVisionTasks()`.
* The path must match the package version of `MEDIAPIPE_TASKS_VISION_URL` to
* avoid runtime version mismatch errors.
*
* @see scripts/engine-3d.js
* @see scripts/mediapipe-loop.js
*/
export const MEDIAPIPE_WASM_URL = 'https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@0.10.35/wasm';
/**
* URL of the MediaPipe FaceLandmarker `.task` bundle (float16, 478 landmarks).
* Hosted by Google's `mediapipe-models` storage.
*
* @see scripts/mediapipe-loop.js – passed to `FaceLandmarker.createFromOptions()`.
*/
export const MEDIAPIPE_FACE_LANDMARKER_URL = 'https://storage.googleapis.com/mediapipe-models/face_landmarker/face_landmarker/float16/1/face_landmarker.task';
/**
* URL of the MediaPipe ImageEmbedder model bundle (MobileNetV3 Small, float32).
* Produces the embedding vector consumed by the 3D recognition pipeline.
*
* @see scripts/engine-3d.js – passed to `ImageEmbedder.createFromOptions()`.
*/
export const MEDIAPIPE_IMAGE_EMBEDDER_URL = 'https://storage.googleapis.com/mediapipe-models/image_embedder/mobilenet_v3_small/float32/1/mobilenet_v3_small.tflite';
/**
* Pre-built TinyFaceDetector options reused across every face-api detection
* call so the inference parameters stay consistent between the live loop, the
* efficacy composite, and the save/find pipelines. `scoreThreshold` is the
* minimum confidence for a face to be reported; `inputSize` is the square
* input dimension fed to the detector (larger = more accurate, slower).
*
* @see scripts/engine.js – `detectFaceInCam`, `runEffectPass`, `compositeAndDetect`.
*/
export const DETECTOR_OPTIONS = new faceapi.TinyFaceDetectorOptions({
inputSize: 416,
scoreThreshold: 0.5
});
/**
* Defaults for the in-app one-second video recording feature. Mode selects
* between a direct browser download and an HTTP POST to a backend endpoint;
* the upload contract is documented inline so the backend implementer doesn't
* need to read the recording code.
*
* @see scripts/camera.js – `recordOneSecond()` reads `mode`, `uploadEndpoint`, `durationMs`.
*/
export const RECORDING_CONFIG = {
// Mode of operation: 'queue' keeps the recorded Blob in the browser so the
// upload/consent flow can decide whether it ever leaves the device.
mode: 'queue',
// Endpoint used by the consented submit action.
// Expected backend contract:
// - Method: POST
// - Content-Type: multipart/form-data
// - Payload field: 'video' (the recording blob)
// - Required field: 'consent_version'
// - Response: { ok, uploadId, deleteToken }
uploadEndpoint: '/api/uploads',
// Duration of the recording in milliseconds (default: 2 seconds).
durationMs: 2000
};
export const UPLOAD_CONSENT_VERSION = '2026-07-v1';
export const APP_VERSION = '0.1.0';