diff --git a/docs/MEDIEN.md b/docs/MEDIEN.md
index 83bce7a..8f435e5 100644
--- a/docs/MEDIEN.md
+++ b/docs/MEDIEN.md
@@ -22,6 +22,14 @@ Das Logo wird 32 bis 40 px hoch angezeigt. Ein querformatiges Logo ohne Rand wir
| `header.jpg` (oder `.webp`, `.png`) | Bild über die ganze Breite oben | Querformat, mindestens 2400 px breit. Ohne Datei erscheint die Luftaufnahme der Villa |
| `header.mp4` (optional) | Video statt Standbild, läuft stumm in Schleife | Kurz halten (unter 15 s, unter 10 MB). `header.jpg` dient als Vorschaubild |
+## Video unter dem Headerbild
+
+| Datei | Wofür | Hinweis |
+|---|---|---|
+| `intro.mp4` | Video direkt unter dem Headerbild, startet erst nach Klick | Quer- oder Hochformat. Ohne Datei entfällt der Abschnitt |
+| `intro.jpg` (oder `.webp`, `.png`) | Vorschaubild des Videos | Empfohlen: Mit Vorschaubild lädt vom Video vorab nichts |
+| `intro.web.mp4` (optional) | Web-Fassung, wird bevorzugt angezeigt | Erzeugen mit `pnpm media:optimize`, siehe unten |
+
## Team (Ordner `team/`)
Hochformat 3:4 oder 4:5, mindestens 1200 px breit, Gesicht im oberen Drittel. Das Bild wird oben rund (als Bogen) beschnitten.
diff --git a/src/app/page.tsx b/src/app/page.tsx
index 92d8b44..ed8bca7 100644
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -6,6 +6,7 @@ import { AccommodationSection } from "@/components/sections/CampSections";
import { ExpectSection, ScheduleSection } from "@/components/sections/ExpectSections";
import { ClosingSection, FaqSection } from "@/components/sections/FaqSection";
import { AboutSection, ReelsSection, TeamSection } from "@/components/sections/PeopleSections";
+import { IntroVideoSection } from "@/components/sections/IntroVideoSection";
import { PricingSection } from "@/components/sections/PricingSection";
import { ReviewsSection } from "@/components/sections/ReviewsSection";
import { SiteFooter } from "@/components/SiteFooter";
@@ -16,7 +17,7 @@ import { loadPublicPage } from "@/lib/public-page";
import { loadSiteMedia } from "@/lib/site-media";
/*
- * Gliederung nach der Filmcamp-Referenz: Headerbild, Termin, was dich
+ * Gliederung nach der Filmcamp-Referenz: Headerbild, Video, Termin, was dich
* erwartet (die Villa), Tagesablauf, Unterkunft, Preis, Team, Reels,
* Fragen, Abschluss.
*/
@@ -37,6 +38,7 @@ export default async function HomePage() {
+
diff --git a/src/components/VideoSlot.tsx b/src/components/VideoSlot.tsx
index 864faae..facf81e 100644
--- a/src/components/VideoSlot.tsx
+++ b/src/components/VideoSlot.tsx
@@ -1,17 +1,23 @@
import type { Media } from "@/content/site";
+import { optimizedImageUrl } from "@/lib/image-url";
import { MediaFrame } from "./MediaFrame";
+/** Reels sind hoch und hoechstens ein Drittel breit. */
+const POSTER_WIDTH = 1080;
+
type Slot = { name: string | null; caption: string | null; poster: Media | null; src: string | null };
/**
* Ein Video aus dem eigenen Medienverzeichnis, im eigenen Seitenverhaeltnis
- * (quer oder hoch). Es startet nie von selbst; geladen werden vorab nur die
- * Metadaten und das erste Bild als Vorschau (#t=0.1), falls kein
- * Vorschaubild hinterlegt ist. Kein externer Anbieter.
+ * (quer oder hoch). Es startet nie von selbst. Mit Vorschaubild laedt vorab
+ * nichts vom Video, ohne nur Metadaten und erstes Bild (#t=0.1). Kein
+ * externer Anbieter.
*/
export function VideoSlot({ slot, index, showDrafts }: { slot: Slot; index: number; showDrafts: boolean }) {
const label = slot.name ? `Video von ${slot.name}` : `Video ${index + 1}`;
- const poster = slot.poster?.kind === "image" ? slot.poster.src : undefined;
+ // Vorschaubild ueber die Bildoptimierung statt im Original (ein Reel-PNG
+ // hatte 1,3 MB); mit Vorschaubild laedt vom Video vorab nichts.
+ const poster = slot.poster?.kind === "image" ? optimizedImageUrl(slot.poster.src, POSTER_WIDTH) : undefined;
return (
@@ -21,7 +27,7 @@ export function VideoSlot({ slot, index, showDrafts }: { slot: Slot; index: numb
poster={poster}
controls
playsInline
- preload="metadata"
+ preload={poster ? "none" : "metadata"}
aria-label={label}
className="mx-auto block max-h-[80vh] w-full rounded-2xl bg-ink object-contain"
>
diff --git a/src/components/sections/IntroVideoSection.tsx b/src/components/sections/IntroVideoSection.tsx
new file mode 100644
index 0000000..2b606a8
--- /dev/null
+++ b/src/components/sections/IntroVideoSection.tsx
@@ -0,0 +1,44 @@
+import { optimizedImageUrl } from "@/lib/image-url";
+import type { IntroVideo } from "@/lib/site-media";
+
+/** Breite des Vorschaubilds: scharf bis zur vollen Inhaltsbreite. */
+const POSTER_WIDTH = 1920;
+
+/**
+ * Video direkt unter dem Headerbild (intro.mp4 im Medienverzeichnis,
+ * Vorschaubild intro.jpg, docs/MEDIEN.md). Startet nur nach Klick. Mit
+ * Vorschaubild laedt der Browser vorher gar nichts vom Video
+ * (preload="none"); ohne wird nur das erste Bild als Vorschau geholt.
+ */
+export function IntroVideoSection({ video, showDrafts }: { video: IntroVideo; showDrafts: boolean }) {
+ if (!video.src) {
+ if (!showDrafts) return null;
+ return (
+
+
+ Platzhalter: Hier erscheint das Video, sobald intro.mp4 im Medienverzeichnis liegt.
+
+
+ );
+}
diff --git a/src/lib/image-url.ts b/src/lib/image-url.ts
new file mode 100644
index 0000000..3898c4d
--- /dev/null
+++ b/src/lib/image-url.ts
@@ -0,0 +1,15 @@
+/**
+ * URL eines Bildes ueber die Next.js-Bildoptimierung (AVIF/WebP, passende
+ * Breite) fuer Stellen, an denen kein moeglich ist, etwa das
+ * poster-Attribut von