diff --git a/frontend/src/components/HudBar.tsx b/frontend/src/components/HudBar.tsx
new file mode 100644
index 0000000..93011ce
--- /dev/null
+++ b/frontend/src/components/HudBar.tsx
@@ -0,0 +1,128 @@
+import { useQuery } from '@tanstack/react-query';
+import { Link } from 'react-router-dom';
+import { characterApi, questApi } from '../api/endpoints';
+import { Heart, Zap, Star, Coins, Scroll, Clock } from 'lucide-react';
+import { useState, useEffect } from 'react';
+
+function RegenTimer({ endurance, enduranceMax, lastEnduranceTs }: { endurance: number; enduranceMax: number; lastEnduranceTs: string }) {
+ const [now, setNow] = useState(Date.now());
+
+ useEffect(() => {
+ if (endurance >= enduranceMax) return;
+ const id = setInterval(() => setNow(Date.now()), 1000);
+ return () => clearInterval(id);
+ }, [endurance, enduranceMax]);
+
+ if (endurance >= enduranceMax) return null;
+
+ // Regen = 1pt every 3min = 180s
+ const elapsedMs = now - new Date(lastEnduranceTs).getTime();
+ const elapsedInCycle = elapsedMs % (3 * 60 * 1000);
+ const remainingMs = 3 * 60 * 1000 - elapsedInCycle;
+ const remainingSec = Math.max(0, Math.floor(remainingMs / 1000));
+ const min = Math.floor(remainingSec / 60);
+ const sec = remainingSec % 60;
+
+ return (
+
+
+ +1 dans {min}:{sec.toString().padStart(2, '0')}
+
+ );
+}
+
+export function HudBar() {
+ const { data: char } = useQuery({
+ queryKey: ['character'],
+ queryFn: characterApi.me,
+ refetchInterval: 30_000, // refresh every 30s for endurance updates
+ });
+
+ const { data: activeQuests } = useQuery({
+ queryKey: ['questsActive'],
+ queryFn: questApi.active,
+ refetchInterval: 60_000,
+ });
+
+ if (!char) return null;
+
+ const endurance = (char as any).enduranceCurrent ?? (char as any).endurance ?? 0;
+ const xpNext = (char as any).xpToNextLevel ?? Math.round(100 * Math.pow(char.level, 1.5));
+ const questCount = activeQuests?.filter((pq: any) => pq.status === 'active').length ?? 0;
+ const questReady = activeQuests?.filter((pq: any) => pq.status === 'completed').length ?? 0;
+
+ return (
+
+ {/* Name + Level */}
+
+ đž
+ {char.name}
+ Niv.{char.level}
+
+
+ |
+
+ {/* HP */}
+
+
+
+ {char.hpCurrent}/{char.hpMax}
+
+
+
+ |
+
+ {/* Endurance + timer */}
+
+
+
+ {endurance}/{char.enduranceMax}
+
+ {(char as any).lastEnduranceTs && (
+
+ )}
+
+
+ |
+
+ {/* XP */}
+
+
+ {char.xp}/{xpNext}
+
+
+ |
+
+ {/* Gold */}
+
+
+ {char.gold}
+
+
+ |
+
+ {/* Quests */}
+
+ 0 ? '#f4c94e' : '#6b7a99'} />
+ {questCount} quĂȘte{questCount !== 1 ? 's' : ''}
+ {questReady > 0 && (
+ ({questReady} prĂȘte{questReady > 1 ? 's' : ''} !)
+ )}
+
+
+ );
+}
diff --git a/frontend/src/components/Layout.tsx b/frontend/src/components/Layout.tsx
index 42ee373..27b3f56 100644
--- a/frontend/src/components/Layout.tsx
+++ b/frontend/src/components/Layout.tsx
@@ -1,6 +1,7 @@
import { Link, useLocation } from 'react-router-dom';
import { useAuth } from '../context/AuthContext';
import { Swords, Package, Hammer, User, LogOut, Shield, Scroll } from 'lucide-react';
+import { HudBar } from './HudBar';
const NAV = [
{ to: '/dashboard', icon: User, label: 'Personnage' },
@@ -44,6 +45,7 @@ export function Layout({ children }: { children: React.ReactNode }) {
)}
+
{/* Sidebar nav */}