DistractIQ / src /lib /engine.ts
github-actions
Initial clean deploy
7ff860b
Raw
History Blame Contribute Delete
4.9 kB
// DistractIQ deterministic prediction engine
// Implements the spec formulas exactly.
export interface FocusInputs {
study_hours: number;
phone_hours: number;
social_hours: number;
sleep_hours: number;
stress_level: number; // 1-10
notifications: number;
}
export interface FocusOutputs {
distraction_score: number;
productivity: number;
focus_score: number;
risk: "HIGH" | "LOW";
risk_reasons: string[];
xp_gained: number;
deep_focus_hours: number;
advisories: string[];
persona: { title: string; caption: string; emoji: string };
}
const clamp = (v: number, min: number, max: number) => Math.max(min, Math.min(max, v));
export function computeDistraction(i: FocusInputs): number {
const raw = i.phone_hours * 8 + i.social_hours * 12 + i.notifications / 10 + i.stress_level * 5;
return Math.round(clamp(raw, 0, 100));
}
export function computeProductivity(i: FocusInputs): number {
const raw = i.study_hours * 15 + i.sleep_hours * 5 - (i.phone_hours * 4 + i.social_hours * 6 + i.stress_level * 8) + 30;
return Math.round(clamp(raw, 0, 100));
}
export function computeFocusScore(distraction: number, productivity: number): number {
// Half-doughnut: invert distraction, weight productivity
return Math.round(clamp(productivity * 0.6 + (100 - distraction) * 0.4, 0, 100));
}
export function computeRisk(i: FocusInputs, distraction: number): { risk: "HIGH" | "LOW"; reasons: string[] } {
const reasons: string[] = [];
if (i.phone_hours > 6 && i.study_hours < 3) reasons.push("Phone use exceeds 6h with under 3h of study");
if (i.social_hours > 4) reasons.push("Social media exceeds 4h");
if (i.stress_level > 8 && i.sleep_hours < 5) reasons.push("High stress combined with sleep deprivation");
if (distraction > 65) reasons.push("Distraction Score above critical threshold (65)");
return { risk: reasons.length > 0 ? "HIGH" : "LOW", reasons };
}
export function computeAdvisories(i: FocusInputs): string[] {
const out: string[] = [];
if (i.stress_level > 7) out.push("Stress is blocking your deep work capacity.");
if (i.sleep_hours < 6) out.push("Sleep deprivation is a hidden productivity killer.");
if (i.notifications > 150) out.push("Your notification density is triggering severe context-switching.");
if (i.phone_hours > 6) out.push("Excessive phone time is fragmenting your attention.");
if (i.social_hours > 4) out.push("Social media is the leading cause of dopamine loops today.");
return out;
}
export function derivePersona(focus: number, productivity: number, distraction: number): { title: string; caption: string; emoji: string } {
if (focus >= 80) return { title: "Deep Work Ninja", emoji: "🥷", caption: "Silent. Focused. Untouchable. You operate in flow others only read about." };
if (focus >= 65) return { title: "Momentum Maker", emoji: "🚀", caption: "Solid rhythm — protect your peak hours and you'll hit elite tier." };
if (productivity >= 50 && distraction < 50) return { title: "Balanced Builder", emoji: "⚖️", caption: "You're stitching focus and rest together — keep refining the edges." };
if (distraction >= 70) return { title: "Scroll Hostage", emoji: "🪤", caption: "The feed is winning. Time to reclaim the next 25 minutes." };
if (productivity < 35) return { title: "Drift Mode", emoji: "🌫️", caption: "Low signal day. One small block of deep work resets the whole week." };
return { title: "Focus Apprentice", emoji: "🎯", caption: "Building the habit. Small, repeatable wins compound fast." };
}
export function computeAll(i: FocusInputs): FocusOutputs {
const distraction = computeDistraction(i);
const productivity = computeProductivity(i);
const focus = computeFocusScore(distraction, productivity);
const { risk, reasons } = computeRisk(i, distraction);
const xp = Math.max(0, Math.round(productivity / 3));
return {
distraction_score: distraction,
productivity,
focus_score: focus,
risk,
risk_reasons: reasons,
xp_gained: xp,
deep_focus_hours: Math.round(i.study_hours * (productivity / 100) * 10) / 10,
advisories: computeAdvisories(i),
persona: derivePersona(focus, productivity, distraction),
};
}
// Constraint validation
export function validateConstraints(i: FocusInputs): string[] {
const errors: string[] = [];
if (i.study_hours + i.phone_hours + i.sleep_hours > 24) {
errors.push("Study + Phone + Sleep cannot exceed 24 hours.");
}
if (i.social_hours > i.phone_hours) {
errors.push("Social media hours cannot exceed total phone hours.");
}
return errors;
}
// XP / level helpers
export const XP_PER_LEVEL = 500;
export const levelFromXp = (xp: number) => Math.floor(xp / XP_PER_LEVEL) + 1;
export const xpInLevel = (xp: number) => xp % XP_PER_LEVEL;
export function isNightMode(): boolean {
const hour = new Date().getHours();
return hour >= 22 || hour < 5;
}