diff --git a/package.json b/package.json
index d2605742e..88b618718 100644
--- a/package.json
+++ b/package.json
@@ -86,9 +86,9 @@
},
"scripts": {
"dev": "react-scripts start",
- "start:nolint": "npx --yes create-react-play@latest -p && react-scripts start",
- "start": "npx --yes create-react-play@latest -p && npm run lint && react-scripts start",
- "build": "npx --yes create-react-play@latest -p && react-scripts build",
+ "start:nolint": "npx --yes create-react-play@latest -p && node scripts/sanitize-play-exports.cjs && react-scripts start",
+ "start": "npx --yes create-react-play@latest -p && node scripts/sanitize-play-exports.cjs && npm run lint && react-scripts start",
+ "build": "npx --yes create-react-play@latest -p && node scripts/sanitize-play-exports.cjs && react-scripts build",
"snap": "react-snap",
"test": "react-scripts test",
"eject": "react-scripts eject",
diff --git a/scripts/sanitize-play-exports.cjs b/scripts/sanitize-play-exports.cjs
new file mode 100644
index 000000000..93c0f8b81
--- /dev/null
+++ b/scripts/sanitize-play-exports.cjs
@@ -0,0 +1,86 @@
+#!/usr/bin/env node
+'use strict';
+
+const fs = require('fs');
+const path = require('path');
+
+const indexPath = path.join(process.cwd(), 'src', 'plays', 'index.js');
+
+if (!fs.existsSync(indexPath)) {
+ console.warn(`[sanitize-play-exports] Skipped: file not found at ${indexPath}`);
+ process.exit(0);
+}
+
+const source = fs.readFileSync(indexPath, 'utf8');
+const newline = source.includes('\r\n') ? '\r\n' : '\n';
+const hasTrailingNewline = source.endsWith('\n');
+const lines = source.split(/\r?\n/);
+
+const exportLinePattern = /^(\s*export\s*\{\s*default\s+as\s+)([^}]+?)(\s*\}\s*from\s*['"][^'"]+['"]\s*;?\s*)$/;
+const isValidIdentifier = (value) => /^[$A-Z_a-z][$0-9A-Z_a-z]*$/.test(value);
+
+const toPascalCase = (value) => {
+ const chunks = value
+ .replace(/([a-z0-9])([A-Z])/g, '$1 $2')
+ .split(/[^0-9A-Z_a-z$]+/)
+ .filter(Boolean);
+
+ let identifier = chunks
+ .map((chunk) => chunk.charAt(0).toUpperCase() + chunk.slice(1))
+ .join('');
+
+ if (identifier.length === 0) {
+ identifier = 'Play';
+ }
+
+ if (!/^[$A-Z_a-z]/.test(identifier)) {
+ identifier = `Play${identifier}`;
+ }
+
+ return identifier;
+};
+
+const usedAliases = new Set();
+let updateCount = 0;
+
+const nextLines = lines.map((line) => {
+ const match = line.match(exportLinePattern);
+ if (match == null) {
+ return line;
+ }
+
+ const [, prefix, rawAlias, suffix] = match;
+ const currentAlias = rawAlias.trim();
+ let nextAlias = currentAlias;
+
+ if (!isValidIdentifier(currentAlias)) {
+ nextAlias = toPascalCase(currentAlias);
+ }
+
+ const aliasBase = nextAlias;
+ let duplicateIndex = 2;
+ while (usedAliases.has(nextAlias)) {
+ nextAlias = `${aliasBase}${duplicateIndex}`;
+ duplicateIndex += 1;
+ }
+ usedAliases.add(nextAlias);
+
+ if (nextAlias !== currentAlias) {
+ updateCount += 1;
+ return `${prefix}${nextAlias}${suffix}`;
+ }
+
+ return line;
+});
+
+let nextSource = nextLines.join(newline);
+if (hasTrailingNewline) {
+ nextSource += newline;
+}
+
+if (nextSource !== source) {
+ fs.writeFileSync(indexPath, nextSource, 'utf8');
+ console.log(`[sanitize-play-exports] Updated ${updateCount} export alias(es).`);
+} else {
+ console.log('[sanitize-play-exports] No invalid aliases found.');
+}
diff --git a/src/plays/bmr-tdee-calculator/BmrTdeeCalculator.jsx b/src/plays/bmr-tdee-calculator/BmrTdeeCalculator.jsx
new file mode 100644
index 000000000..31a4ae1fa
--- /dev/null
+++ b/src/plays/bmr-tdee-calculator/BmrTdeeCalculator.jsx
@@ -0,0 +1,263 @@
+import PlayHeader from 'common/playlists/PlayHeader';
+import { useState } from 'react';
+import './styles.css';
+
+// WARNING: Do not change the entry component name
+function BmrTdeeCalculator(props) {
+ const [gender, setGender] = useState('male');
+ const [age, setAge] = useState('');
+ const [weight, setWeight] = useState('');
+ const [height, setHeight] = useState('');
+ const [activityLevel, setActivityLevel] = useState('1.2');
+ const [unit, setUnit] = useState('metric');
+ const [result, setResult] = useState(null);
+
+ const activityOptions = [
+ { value: '1.2', label: 'Sedentary', desc: 'Little or no exercise' },
+ { value: '1.375', label: 'Lightly Active', desc: 'Exercise 1-3 days/week' },
+ { value: '1.55', label: 'Moderately Active', desc: 'Exercise 3-5 days/week' },
+ { value: '1.725', label: 'Very Active', desc: 'Exercise 6-7 days/week' },
+ { value: '1.9', label: 'Extra Active', desc: 'Very hard exercise or physical job' }
+ ];
+
+ const calculateBMR = () => {
+ const ageNum = parseFloat(age);
+ let weightKg = parseFloat(weight);
+ let heightCm = parseFloat(height);
+
+ if (!ageNum || !weightKg || !heightCm) {
+ return;
+ }
+
+ // Convert imperial to metric if needed
+ if (unit === 'imperial') {
+ weightKg = weightKg * 0.453592; // lbs to kg
+ heightCm = heightCm * 2.54; // inches to cm
+ }
+
+ // Mifflin-St Jeor Equation
+ let bmr;
+ if (gender === 'male') {
+ bmr = 10 * weightKg + 6.25 * heightCm - 5 * ageNum + 5;
+ } else {
+ bmr = 10 * weightKg + 6.25 * heightCm - 5 * ageNum - 161;
+ }
+
+ const activity = parseFloat(activityLevel);
+ const tdee = bmr * activity;
+
+ setResult({
+ bmr: Math.round(bmr),
+ tdee: Math.round(tdee),
+ deficit: Math.round(tdee - 500),
+ surplus: Math.round(tdee + 500)
+ });
+ };
+
+ const handleReset = () => {
+ setGender('male');
+ setAge('');
+ setWeight('');
+ setHeight('');
+ setActivityLevel('1.2');
+ setUnit('metric');
+ setResult(null);
+ };
+
+ return (
+
+
+
+
+
BMR & TDEE Calculator
+
+ Calculate your Basal Metabolic Rate and Total Daily Energy Expenditure
+
+
+
+ {/* Unit Toggle */}
+
+
+
+
+
+
+
+
+ {/* Gender */}
+
+
+
+
+
+
+
+
+ {/* Age */}
+
+
+ setAge(e.target.value)}
+ />
+
+
+ {/* Weight */}
+
+
+ setWeight(e.target.value)}
+ />
+
+
+ {/* Height */}
+
+
+ setHeight(e.target.value)}
+ />
+
+
+ {/* Activity Level */}
+
+
+
+
+
+ {/* Buttons */}
+
+
+
+
+
+
+ {/* Results */}
+ {result && (
+
+
Your Results
+
+
+ BMR
+ {result.bmr}
+ cal/day
+ Calories at complete rest
+
+
+ TDEE
+ {result.tdee}
+ cal/day
+ Maintenance calories
+
+
+ Weight Loss
+ {result.deficit}
+ cal/day
+ TDEE − 500 cal deficit
+
+
+ Weight Gain
+ {result.surplus}
+ cal/day
+ TDEE + 500 cal surplus
+
+
+
+
+
What do these numbers mean?
+
+ -
+ BMR — The calories your body burns at complete rest just to keep
+ you alive (breathing, circulation, cell production).
+
+ -
+ TDEE — Your total calories burned per day including physical
+ activity. Eat this amount to maintain weight.
+
+ -
+ Weight Loss — A 500 cal/day deficit leads to ~0.45 kg (1 lb)
+ lost per week.
+
+ -
+ Weight Gain — A 500 cal/day surplus leads to ~0.45 kg (1 lb)
+ gained per week.
+
+
+
+ * Calculated using the Mifflin-St Jeor Equation, considered the most accurate BMR
+ formula.
+
+
+
+ )}
+
+
+
+ );
+}
+
+export default BmrTdeeCalculator;
diff --git a/src/plays/bmr-tdee-calculator/Readme.md b/src/plays/bmr-tdee-calculator/Readme.md
new file mode 100644
index 000000000..ed08e5d1c
--- /dev/null
+++ b/src/plays/bmr-tdee-calculator/Readme.md
@@ -0,0 +1,41 @@
+# BMR & TDEE Calculator
+
+A calculator to determine your Basal Metabolic Rate (BMR) and Total Daily Energy Expenditure (TDEE) using the Mifflin-St Jeor Equation.
+
+## Play Demographic
+
+- Language: js
+- Level: Beginner
+
+## Creator Information
+
+- User: aniketmishra-0
+- GitHub Link: https://github.com/aniketmishra-0
+- Blog:
+- Video:
+
+## Implementation Details
+
+This play implements a BMR & TDEE calculator with the following features:
+
+- **BMR Calculation** using the Mifflin-St Jeor Equation (most accurate modern formula)
+- **TDEE Calculation** based on 5 activity levels
+- **Metric & Imperial** unit support (kg/cm and lbs/inches)
+- **Weight management guidance** showing calorie targets for loss/gain
+- Clean, responsive UI with smooth result animations
+
+### Formulas Used
+
+**Mifflin-St Jeor Equation:**
+- Male: BMR = 10 × weight(kg) + 6.25 × height(cm) − 5 × age − 5
+- Female: BMR = 10 × weight(kg) + 6.25 × height(cm) − 5 × age − 161
+
+**TDEE = BMR × Activity Multiplier**
+
+## Consideration
+
+- Results are estimates and should not replace professional medical advice.
+
+## Resources
+
+- [Mifflin-St Jeor Equation](https://en.wikipedia.org/wiki/Basal_metabolic_rate)
diff --git a/src/plays/bmr-tdee-calculator/cover.svg b/src/plays/bmr-tdee-calculator/cover.svg
new file mode 100644
index 000000000..956ed81f9
--- /dev/null
+++ b/src/plays/bmr-tdee-calculator/cover.svg
@@ -0,0 +1,22 @@
+
diff --git a/src/plays/bmr-tdee-calculator/styles.css b/src/plays/bmr-tdee-calculator/styles.css
new file mode 100644
index 000000000..c69985b28
--- /dev/null
+++ b/src/plays/bmr-tdee-calculator/styles.css
@@ -0,0 +1,292 @@
+.bmr-tdee-container {
+ max-width: 680px;
+ margin: 0 auto;
+ padding: 2rem 1.5rem;
+ font-family: var(--ff-default, 'Inter', sans-serif);
+}
+
+.bmr-tdee-title {
+ font-size: 1.75rem;
+ font-weight: 700;
+ text-align: center;
+ margin-bottom: 0.25rem;
+ color: var(--color-neutral-90, #1a1a2e);
+}
+
+.bmr-tdee-subtitle {
+ text-align: center;
+ color: var(--color-neutral-50, #6b7280);
+ font-size: 0.95rem;
+ margin-bottom: 2rem;
+}
+
+/* Form */
+.bmr-tdee-form {
+ background: var(--color-neutral-10, #ffffff);
+ border: 1px solid var(--color-neutral-30, #e5e7eb);
+ border-radius: 1rem;
+ padding: 1.5rem;
+ display: flex;
+ flex-direction: column;
+ gap: 1.25rem;
+}
+
+.bmr-tdee-field {
+ display: flex;
+ flex-direction: column;
+ gap: 0.4rem;
+}
+
+.bmr-tdee-label {
+ font-size: 0.85rem;
+ font-weight: 600;
+ color: var(--color-neutral-70, #374151);
+}
+
+.bmr-tdee-input,
+.bmr-tdee-select {
+ padding: 0.65rem 0.85rem;
+ border: 1px solid var(--color-neutral-30, #d1d5db);
+ border-radius: 0.5rem;
+ font-size: 0.95rem;
+ color: var(--color-neutral-90, #1f2937);
+ background: var(--color-neutral-10, #fff);
+ transition: border-color 0.2s ease, box-shadow 0.2s ease;
+ outline: none;
+}
+
+.bmr-tdee-input:focus,
+.bmr-tdee-select:focus {
+ border-color: var(--color-brand-primary, #00f2fe);
+ box-shadow: 0 0 0 3px rgba(0, 242, 254, 0.15);
+}
+
+.bmr-tdee-input::placeholder {
+ color: var(--color-neutral-40, #9ca3af);
+}
+
+/* Toggle group */
+.bmr-tdee-toggle-group {
+ display: flex;
+ gap: 0.5rem;
+}
+
+.bmr-tdee-toggle-btn {
+ flex: 1;
+ padding: 0.55rem 0.75rem;
+ border: 1px solid var(--color-neutral-30, #d1d5db);
+ border-radius: 0.5rem;
+ background: var(--color-neutral-10, #fff);
+ color: var(--color-neutral-60, #6b7280);
+ font-size: 0.85rem;
+ font-weight: 500;
+ cursor: pointer;
+ transition: all 0.2s ease;
+}
+
+.bmr-tdee-toggle-btn:hover {
+ border-color: var(--color-brand-primary, #00f2fe);
+}
+
+.bmr-tdee-toggle-btn.active {
+ background: var(--color-brand-primary, #00f2fe);
+ border-color: var(--color-brand-primary, #00f2fe);
+ color: var(--color-neutral-90, #1a1a2e);
+ font-weight: 600;
+}
+
+/* Buttons */
+.bmr-tdee-btn-group {
+ display: flex;
+ gap: 0.75rem;
+ margin-top: 0.5rem;
+}
+
+.bmr-tdee-btn {
+ flex: 1;
+ padding: 0.7rem 1rem;
+ border: none;
+ border-radius: 0.5rem;
+ font-size: 0.95rem;
+ font-weight: 600;
+ cursor: pointer;
+ transition: all 0.2s ease;
+}
+
+.bmr-tdee-btn-primary {
+ background: var(--color-brand-primary, #00f2fe);
+ color: var(--color-neutral-90, #1a1a2e);
+}
+
+.bmr-tdee-btn-primary:hover {
+ opacity: 0.9;
+ transform: translateY(-1px);
+ box-shadow: 0 4px 12px rgba(0, 242, 254, 0.3);
+}
+
+.bmr-tdee-btn-secondary {
+ background: transparent;
+ border: 1px solid var(--color-neutral-30, #d1d5db);
+ color: var(--color-neutral-60, #6b7280);
+}
+
+.bmr-tdee-btn-secondary:hover {
+ border-color: var(--color-neutral-50, #9ca3af);
+ color: var(--color-neutral-80, #374151);
+}
+
+/* Results */
+.bmr-tdee-results {
+ margin-top: 2rem;
+ animation: bmrFadeIn 0.4s ease;
+}
+
+@keyframes bmrFadeIn {
+ from {
+ opacity: 0;
+ transform: translateY(12px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+.bmr-tdee-results-title {
+ font-size: 1.25rem;
+ font-weight: 700;
+ text-align: center;
+ margin-bottom: 1.25rem;
+ color: var(--color-neutral-90, #1a1a2e);
+}
+
+.bmr-tdee-results-grid {
+ display: grid;
+ grid-template-columns: repeat(2, 1fr);
+ gap: 1rem;
+}
+
+.bmr-tdee-result-card {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ padding: 1.25rem 1rem;
+ border-radius: 0.75rem;
+ border: 1px solid var(--color-neutral-30, #e5e7eb);
+ background: var(--color-neutral-10, #fff);
+ transition: transform 0.2s ease, box-shadow 0.2s ease;
+}
+
+.bmr-tdee-result-card:hover {
+ transform: translateY(-2px);
+ box-shadow: 0 6px 20px rgba(0, 0, 0, 0.08);
+}
+
+.bmr-tdee-card-bmr {
+ border-top: 3px solid #6366f1;
+}
+
+.bmr-tdee-card-tdee {
+ border-top: 3px solid #00f2fe;
+}
+
+.bmr-tdee-card-deficit {
+ border-top: 3px solid #f59e0b;
+}
+
+.bmr-tdee-card-surplus {
+ border-top: 3px solid #10b981;
+}
+
+.bmr-tdee-result-label {
+ font-size: 0.75rem;
+ font-weight: 700;
+ text-transform: uppercase;
+ letter-spacing: 0.05em;
+ color: var(--color-neutral-50, #6b7280);
+ margin-bottom: 0.25rem;
+}
+
+.bmr-tdee-result-value {
+ font-size: 2rem;
+ font-weight: 800;
+ color: var(--color-neutral-90, #1a1a2e);
+ line-height: 1.1;
+}
+
+.bmr-tdee-result-unit {
+ font-size: 0.8rem;
+ color: var(--color-neutral-50, #9ca3af);
+ margin-bottom: 0.35rem;
+}
+
+.bmr-tdee-result-desc {
+ font-size: 0.75rem;
+ color: var(--color-neutral-40, #9ca3af);
+ text-align: center;
+}
+
+/* Info section */
+.bmr-tdee-info {
+ margin-top: 1.75rem;
+ background: var(--color-neutral-10, #f9fafb);
+ border: 1px solid var(--color-neutral-30, #e5e7eb);
+ border-radius: 0.75rem;
+ padding: 1.25rem 1.5rem;
+}
+
+.bmr-tdee-info h4 {
+ font-size: 1rem;
+ font-weight: 700;
+ margin-bottom: 0.75rem;
+ color: var(--color-neutral-90, #1f2937);
+}
+
+.bmr-tdee-info ul {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+ display: flex;
+ flex-direction: column;
+ gap: 0.6rem;
+}
+
+.bmr-tdee-info li {
+ font-size: 0.85rem;
+ color: var(--color-neutral-60, #4b5563);
+ line-height: 1.5;
+}
+
+.bmr-tdee-info li strong {
+ color: var(--color-neutral-80, #1f2937);
+}
+
+.bmr-tdee-info-note {
+ margin-top: 0.75rem;
+ font-size: 0.75rem;
+ color: var(--color-neutral-40, #9ca3af);
+ font-style: italic;
+}
+
+/* Responsive */
+@media screen and (max-width: 520px) {
+ .bmr-tdee-container {
+ padding: 1rem;
+ }
+
+ .bmr-tdee-title {
+ font-size: 1.4rem;
+ }
+
+ .bmr-tdee-results-grid {
+ grid-template-columns: 1fr;
+ }
+
+ .bmr-tdee-toggle-group {
+ flex-direction: column;
+ }
+
+ .bmr-tdee-result-value {
+ font-size: 1.6rem;
+ }
+}