diff --git a/apps/web/src/App.tsx b/apps/web/src/App.tsx
index 92936cc..0b53aaa 100644
--- a/apps/web/src/App.tsx
+++ b/apps/web/src/App.tsx
@@ -1,7 +1,8 @@
import { lazy, Suspense } from 'react';
-import { Link, Route, Routes } from 'react-router-dom';
+import { Link, Route, Routes, useLocation } from 'react-router-dom';
import SearchPage from './pages/SearchPage';
import ModPage from './pages/ModPage';
+import ModHeader from './components/ModHeader';
// The full-setup view and the bgm/tabletop pages pull in the whole three.js
// stack (Scene + all mesh viewers + @tts/tabletop). Lazy-load them so that
@@ -18,22 +19,29 @@ const SetupsPage = lazy(() => import('./pages/SetupsPage'));
const SetupPage = lazy(() => import('./pages/SetupPage'));
export default function App() {
+ const { pathname } = useLocation();
+ const isModRoute = pathname.startsWith('/mod/');
+
return (
-
-
- TTS Workshop
-
-
+ )}
diff --git a/apps/web/src/components/ModHeader.tsx b/apps/web/src/components/ModHeader.tsx
new file mode 100644
index 0000000..913c43b
--- /dev/null
+++ b/apps/web/src/components/ModHeader.tsx
@@ -0,0 +1,59 @@
+import { useMemo } from 'react';
+import { Link, useParams } from 'react-router-dom';
+import { buildTree, collectRefs } from '@tts/extract';
+import { useModStore } from '../stores/modStore';
+import { useSearchStore } from '../stores/searchStore';
+import { modFileUrl } from '../api';
+
+/**
+ * Replaces the global site header on the mod page: thumbnail, game name, and
+ * a subheader with the mod id and stats, plus download/setup links styled like
+ * the Search/BGM nav.
+ */
+export default function ModHeader() {
+ const { id } = useParams<{ id: string }>();
+ const { mod } = useModStore();
+ const item = useSearchStore((s) => s.items.find((i) => i.id === id));
+ const tree = useMemo(() => (mod ? buildTree(mod.mod) : []), [mod]);
+ const refs = useMemo(() => (mod ? collectRefs(mod.mod) : []), [mod]);
+ // Prefer the metadata fetched with the save (survives a refresh); fall back
+ // to the search result for the brief moment before the save loads.
+ const title = mod?.title ?? item?.title;
+ const previewImageUrl = mod?.previewImageUrl ?? item?.previewImageUrl;
+
+ return (
+