Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/piratta/gymApp/llms.txt

Use this file to discover all available pages before exploring further.

FocusFlow implements four validated skinfold protocols in src/lib/plicometria.ts. This page documents the exact mathematical formulas, site selections, and coefficient tables used by computePlicometriaValues() to transform raw millimetre measurements into actionable body-composition metrics. All results are stored in a PlicometriaLog document in Firestore.
All formulas assume skinfold measurements in millimetres (mm) and bodyweight in kilograms (kg). Body density is expressed in g/cm³.

computePlicometriaValues

The main computation function. It accepts raw skinfold inputs and returns the five derived body-composition values. The correct sub-formula is selected automatically based on protocolId and biologicalSex.
export function computePlicometriaValues(params: {
  weight: number;
  protocolId: "3-fold" | "4-fold" | "7-fold" | "yuhasz";
  biologicalSex: "MALE" | "FEMALE";
  age: number;
  pectoral?: number;
  abdominal?: number;
  musloAnterior?: number;
  triceps?: number;
  suprailiaco?: number;
  biceps?: number;
  subescapular?: number;
  axilarMedio?: number;
}): {
  sumaPliegues: number;
  densidadCorporal: number;
  porcentajeGrasa: number;
  masaGrasa: number;
  masaMagra: number;
}

Input parameters

ParameterTypeDescription
weightnumberAthlete’s bodyweight in kg
protocolIdstringSkinfold protocol to apply
biologicalSex"MALE" | "FEMALE"Determines which sex-specific coefficients are used
agenumberAthlete’s age in years at time of measurement
pectoralaxilarMedionumber?Individual skinfold measurements in mm (defaults to 0)

Output

FieldTypeDescription
sumaPlieguesnumberSum of the skinfolds used by the selected protocol (mm)
densidadCorporalnumberBody density in g/cm³ (5 d.p.)
porcentajeGrasanumberBody fat percentage (clamped 2–60%, 2 d.p.)
masaGrasanumberFat mass in kg (2 d.p.)
masaMagranumberLean mass in kg (2 d.p.)

Jackson-Pollock 3-Fold Protocol ("3-fold")

A three-site Jackson-Pollock equation validated for healthy adults. Site selection differs by biological sex. Measurement sites:
  • Males: Pectoral + Abdominal + Muslo anterior
  • Females: Tríceps + Suprailiaco + Muslo anterior
Where S = sum of the three skinfolds in mm and D = body density in g/cm³. Males formula:
D = 1.10938
  − 0.0008267 × S
  + 0.0000016 × S²
  − 0.0002574 × Age
Females formula:
D = 1.0994921
  − 0.0009929 × S
  + 0.0000023 × S²
  − 0.0001392 × Age

Durnin-Womersley 4-Fold Protocol ("4-fold")

The Durnin-Womersley protocol uses four sites and applies age- and sex-stratified logarithmic regression coefficients to account for fat distribution changes across the lifespan. Measurement sites: Tríceps + Bíceps + Subescapular + Suprailiaco Formula:
D = C − m × log₁₀(S)
Where S = sum of all four skinfolds (mm), and C and m are looked up from the coefficient table below based on the athlete’s age group and biological sex.
log10(S) uses Math.log10(Math.max(1, sumaPliegues)) in the implementation to prevent a log(0) domain error when all measurements are zero.

Coefficient table

Males:
Age groupCm
< 201.16200.0630
20–291.16310.0632
30–391.14220.0544
40–491.16200.0700
50+1.17150.0779
Females:
Age groupCm
< 201.15490.0678
20–291.15990.0717
30–391.14230.0632
40–491.13330.0612
50+1.13390.0645

Jackson-Pollock 7-Fold Protocol ("7-fold")

The most comprehensive Jackson-Pollock protocol, using seven measurement sites for greater accuracy across a wider range of body compositions. Measurement sites: Pectoral + Axilar medio + Tríceps + Subescapular + Abdominal + Suprailiaco + Muslo anterior Where S = sum of all seven skinfolds in mm and D = body density. Males formula:
D = 1.112
  − 0.00043499 × S
  + 0.00000055 × S²
  − 0.00028826 × Age
Females formula:
D = 1.097
  − 0.00046971 × S
  + 0.00000056 × S²
  − 0.00012828 × Age

Yuhasz Protocol ("yuhasz")

The Yuhasz protocol bypasses body density entirely, computing body fat percentage directly from the sum of six skinfolds with sex-specific linear regression equations. Measurement sites: Pectoral + Subescapular + Tríceps + Abdominal + Suprailiaco + Muslo anterior Males:
%Fat = 0.1051 × S + 2.585
Females:
%Fat = 0.1548 × S + 3.58
Because Yuhasz produces %Fat directly, densidadCorporal remains at its default value of 1.0 in the returned object — the Siri formula is not applied for this protocol.

Siri Formula — Body Density → Body Fat %

For the 3-fold, 4-fold, and 7-fold protocols, FocusFlow converts body density to body fat percentage using the classic Siri (1956) two-compartment model:
%Fat = (4.95 / D − 4.5) × 100
Where D is the body density in g/cm³ computed by the relevant Jackson-Pollock or Durnin-Womersley equation.
// Siri Formula (applied only when !isDirectGrasa)
porcentajeGrasa = (4.95 / (densidadCorporal || 1)) - 4.5;
porcentajeGrasa = porcentajeGrasa * 100;

Clamping

After the percentage is computed (via Siri or Yuhasz), the result is clamped to a physiologically safe range to guard against extreme outliers caused by measurement error:
// Clamp %Grasa between 2% and 60% for physical safety
porcentajeGrasa = Math.max(2, Math.min(60, porcentajeGrasa));
The 2% lower bound represents the minimum essential fat necessary for physiological function. The 60% upper bound is a conservative ceiling well above clinically observed maximum values, ensuring downstream calculations never produce nonsensical masses.

Derived Values

Once porcentajeGrasa is finalised, fat and lean masses are computed from the athlete’s bodyweight:
masaGrasa (kg) = weight × (porcentajeGrasa / 100)
masaMagra (kg) = weight − masaGrasa
const masaGrasa = weight * (porcentajeGrasa / 100);
const masaMagra = weight - masaGrasa;
All five output values are returned with fixed decimal precision:
return {
  sumaPliegues:     Number(sumaPliegues.toFixed(1)),     // 1 d.p.
  densidadCorporal: Number(densidadCorporal.toFixed(5)), // 5 d.p.
  porcentajeGrasa:  Number(porcentajeGrasa.toFixed(2)),  // 2 d.p.
  masaGrasa:        Number(masaGrasa.toFixed(2)),        // 2 d.p.
  masaMagra:        Number(masaMagra.toFixed(2)),        // 2 d.p.
};

calculateAgeAtDate

A helper function used internally to compute the athlete’s exact age in whole years at the time a plicometría log is recorded. This ensures the age-dependent terms in the 3-fold, 4-fold, and 7-fold formulas reflect the athlete’s age on the day of measurement rather than their current age.
export function calculateAgeAtDate(
  birthDateStr: string,
  logDateStr: string
): number

Parameters

ParameterTypeDescription
birthDateStrstringAthlete’s date of birth in YYYY-MM-DD format
logDateStrstringDate of the plicometría log in YYYY-MM-DD format

Return value

The athlete’s age in whole years on the log date. Returns 30 as a safe default if either date string is missing or cannot be parsed.

Logic

export function calculateAgeAtDate(
  birthDateStr: string,
  logDateStr: string
): number {
  if (!birthDateStr) return 30;
  const birth = new Date(birthDateStr);
  const target = new Date(logDateStr);
  if (isNaN(birth.getTime()) || isNaN(target.getTime())) return 30;

  let age = target.getFullYear() - birth.getFullYear();
  const m = target.getMonth() - birth.getMonth();
  if (m < 0 || (m === 0 && target.getDate() < birth.getDate())) {
    age--;
  }
  return Math.max(0, age);
}
The birthday-boundary check (m < 0 || (m === 0 && date < birthDate)) ensures athletes whose birthday falls later in the measurement year are not counted as a year older than they actually are.
The default fallback of 30 is a deliberate choice: it sits near the centre of most adult training populations, minimising systematic error in age-dependent terms when birth date data is unavailable.

Build docs developers (and LLMs) love