# Handoff: Videogen — Web-App (Desktop-Adaption der Mobile-App) ## Überblick Die bestehende Mobile-App („videogen", Swipe-Feed für Creator-/Produkt-Posts) als Desktop-Web-App. Statt einer schmalen Handy-Spalte im Browser: Icon-Rail links, breite Kopfzeile mit Suche, zentraler Kartenstapel und Detailspalte. Swipen wird durch Maus-Drag, Buttons und Tastatur ersetzt. **Visuelle Sprache: Pinterest Desktop.** Heller Hintergrund, schmale Icon-Leiste ohne Beschriftung, Suchfeld als breite Pille, rote Primäraktion („Merken"), randlose Karten mit 16px-Radius, Masonry-Raster im Profil. Referenz ist die Pinterest-Web-App (`de.pinterest.com`); der Screenshot dafür liegt bisher nicht im Repo, siehe [Offene Punkte](#offene-punkte). **Die Funktionen sind gegenüber dem ersten Entwurf unverändert** — Kartenstapel, Merken/Ablehnen, Undo, Tabs, die vier Screens und das State-Modell bleiben, wie sie waren. Geändert hat sich ausschließlich die Gestaltung. ## Zu den Design-Dateien Die Dateien in diesem Bundle sind **Design-Referenzen in HTML** — Prototypen, die Aussehen und Verhalten zeigen, **kein Produktionscode zum Kopieren**. Aufgabe ist, diese Designs in der bestehenden Umgebung des Ziel-Codebases nachzubauen (React, Vue, Svelte, Next.js …) mit dessen etablierten Patterns und Bibliotheken. Existiert noch keine Umgebung, das passendste Framework wählen (Empfehlung: React + TypeScript, Motion/Framer Motion für die Kartenanimation) und dort umsetzen. Die HTML-Datei ist ein „Design Component"-Format: `Videogen Web.dc.html` enthält Template + Logikklasse, `support.js` ist die Laufzeit dazu. Zum Ansehen: beide Dateien im selben Ordner belassen und die `.dc.html` im Browser öffnen. Die Logikklasse am Dateiende ist lesbarer JS-Code und dient als Referenz für Zustand und Interaktion. ## Fidelity **High-fidelity.** Farben, Typografie, Abstände, Radien, Übergänge und Interaktionen sind final gemeint und sollen pixelgenau nachgebaut werden — mit den Komponenten/Utilities des Ziel-Codebases. --- ## Globales Layout (App-Shell) - Wurzel: `display:flex`, `min-height:100vh`, **`min-width:1180px`** (darunter horizontales Scrollen, die App ist Desktop-only gedacht). - Hintergrund durchgehend `#ffffff`, Grundschrift `#111111`. Keine Verläufe, kein `backdrop-filter`. ### 1. Icon-Rail (links) - Breite `80px`, `flex:none`, `position:sticky; top:0; height:100vh`, `background:#ffffff`, rechte Kante `1px solid #efefef`. Padding `12px 0 16px`, Inhalt zentrierte Flex-Spalte, `gap:8px`. - **Brand**: 32×32 Kreis `#e60023` in einem 48px-Slot, weißes „V" 17px/700. - **Nav-Buttons**: 48×48, `border-radius:50%`, Icon 20px, **ohne Textlabel** — der Name steht im `title`-Attribut und wird als Tooltip gezeigt. - Inaktiv: transparent, Icon `#111111`. Hover: `background:#e9e9e9`. - Aktiv: `background:#111111`, Icon `#ffffff`. Aktiv + Hover: `background:#000000`. - Transition `.12s ease`. - **Umsetzungshinweis:** Die Zustände gehören in Klassen (`.rail`, `.rail.active`), nicht in Inline-Styles. Im Prototyp setzt die `.dc`-Laufzeit `style-hover` mit `!important`; ein inline gesetztes Aktiv-Schwarz würde beim Hover überschrieben und der aktive Button hellte auf. - Reihenfolge oben: **Feed, Profil, Erstellen**. Unten (`margin-top:auto`): **Einstellungen**. - Icons (im Prototyp Unicode-Glyphen als Platzhalter) — **Lucide**: `home`, `user`, `plus`, `settings`. ### 2. Kopfzeile - `padding:12px 16px 4px`, Flex-Zeile, `gap:8px`. - **Suchfeld**: `flex:1`, Höhe `48px`, `border-radius:24px`, `background:#efefef`, `padding:0 16px`, Platzhaltertext „Suchen" 16px `#767676`; links Lupe, rechts Objektiv-Symbol (Lucide `search` und `camera`). - **Konto**: 40px Kreis `linear-gradient(140deg,#b2323c,#5d1620)` mit weißer Initiale 15px/700, daneben 28px Chevron-Button (`▾`, Hover `#e9e9e9`). ### 3. Tab-Leiste - `padding:0 24px`, Unterkante `1px solid #efefef`, Tabs mit `gap:24px`, an der Grundlinie ausgerichtet. - **Tabs**: „Videos", „Folge ich", „Posts". Jeder Tab wechselt den Kartenstapel und springt zurück auf den Feed-Screen (Index/History zurücksetzen). - `padding:0 2px 12px`, Unterkante `3px solid` — aktiv `#111111`, inaktiv `transparent`. - Aktiv: `#111111`, 700. Inaktiv: `#767676`, 500; Hover → `#111111`. Schriftgröße 16px. - **Rechts**: Tageszähler „**NN** heute gesichtet" (Zahl 700 `#111111` mit `tabular-nums`, Rest 13px `#767676`), Stapelzähler „3 / 5" (13px `#767676`, `tabular-nums`) und runder Info-Button 36px (transparent, Hover `#e9e9e9`), der das Kürzel-Panel toggelt. --- ## Screens ### A. Feed (Startansicht) **Zweck:** Karten sichten, merken oder überspringen. **Layout:** `display:grid; grid-template-columns: minmax(0,1fr) 372px; flex:1; min-height:0; overflow:auto`. #### A1 Kartenbühne (linke Spalte) - Zentriert, `padding:26px 20px 30px`, `gap:22px`, `position:relative`. - Bühne: `position:relative; width:min(404px,100%); height:560px; flex:none`. - Es werden **bis zu 3 Karten** gestapelt gerendert (konfigurierbar 1–5). - Karte k (0 = oben): `transform: translate3d(0, -12px·k, 0) scale(1 - 0.045·k)`, `z-index: 10-k`, `pointer-events` nur auf der obersten. - Karte: `position:absolute; inset:0; border-radius:26px` → **`16px`**, `overflow:hidden`, **kein Rahmen**, `box-shadow: 0 1px 20px rgba(0,0,0,.18)`, `touch-action:none; user-select:none; cursor:grab` (beim Ziehen `grabbing`). - Transition: `transform .34s cubic-bezier(.22,.9,.3,1), opacity .3s ease` — während des aktiven Drags `none`. - **Karteninhalt (von unten nach oben gestapelt):** 1. Grundfläche: `linear-gradient(155deg, 0%, 100%)` (pro Karte, siehe Daten unten). 2. Streifen-Overlay: `repeating-linear-gradient(<40+9·i>deg, rgba(255,255,255,.08) 0 2px, transparent 2px 16px)`, `opacity:.5`. (Im Prototyp Platzhalter für das Video-/Bild-Asset — im Produkt liegt hier das Medium.) 3. **Hover-Scrim**: `rgba(0,0,0,.24)`, `opacity` 0 → 1 in `.12s`, nur wenn die Karte gehovert wird. 4. Lesbarkeits-Verlauf: `linear-gradient(180deg, transparent 46%, rgba(0,0,0,.62) 100%)`. 5. **Pills** oben links (`padding:16px`, `gap:8px`): Art („Produkt"/„Video") und Assets („3 Bilder"). `padding:6px 12px; border-radius:16px; background: rgba(255,255,255,.94); color:#111111; font:600 13px`. 6. **Merken-Pille** oben rechts, **nur auf der obersten Karte und erst beim Hover** (`opacity` 0 → 1 in `.12s`): `padding:11px 16px; border-radius:22px; background:#e60023; color:#ffffff; font:700 15px`, Hover `#ad081b`. Klick = dieselbe Aktion wie „Merken"/→. 7. **Caption** mittig, 104px über der Unterkante: `font:600 15px`, `padding:8px 14px`, `border-radius:16px`, `background: rgba(255,255,255,.94)`, `color:#111111`. 8. **Creator-Zeile** unten (`padding:18px`, `gap:12px`, Text weiß): 44px Avatar-Kreis (Farbverlauf, ohne Rand), Name 18px/700 `letter-spacing:-.01em`, Untertitel 14px `rgba(255,255,255,.82)`. 9. **Entscheidungs-Badge** (nur oberste Karte, erscheint ab 40px Drag oder beim Exit): `top:86px`, links bei „GEMERKT" / rechts bei „SKIP", `padding:10px 18px; border-radius:22px; font:700 15px; letter-spacing:.08em`, Text immer `#ffffff`, Fläche `#e60023` (GEMERKT) bzw. `#111111` (SKIP), `rotate(-10deg)` bzw. `rotate(10deg)`, Opacity `min(1, |dx|/110)`, Transition `.16s`. - **Leerzustand** (Stapel durch): Fläche `#f5f5f5`, `radius:16px`, Titel „Alles gesichtet" 20px/700, Text „Für heute sind keine neuen Karten mehr in dieser Ansicht." 15px `#5f5f5f`, roter Pill-Button „Stapel neu laden" (`#e60023`, Hover `#ad081b`, weiß 15px/700, `padding:12px 20px; radius:24px`), Einblendung `fadeIn .3s`. - **Aktions-Buttons** unter der Bühne (`gap:16px`), Hover `scale(1.04)`, Active `scale(.96)`, Transition `.12s`: - ✕ Ablehnen — 56px Kreis, `background:#efefef`, Icon `#111111`, Hover `#e2e2e2`. - ↺ Zurück — 48px Kreis, gleiche Flächen. - **Merken** — roter Pill statt Kreis: Höhe 56px, `padding:0 30px`, `border-radius:28px`, `background:#e60023`, `color:#ffffff`, `font:700 17px`, Hover `#ad081b`. (Icons in der Implementierung: Lucide `x`, `rotate-ccw`; „Merken" trägt Text, kein Icon.) - **Kürzel-Panel** (Info-Button): absolut `right:26px; top:26px`, 250px, `radius:16px`, `background:#ffffff`, `box-shadow: 0 1px 20px rgba(0,0,0,.16)`, `padding:16px`, Einblendung `riseIn .22s`. Inhalt: ← Ablehnen, → Merken, ↑ Zurücknehmen, Maus Karte ziehen. #### A2 Detailspalte (rechts, 372px) - `border-left:1px solid #efefef`, `background:#ffffff`, `padding:28px`, Flex-Spalte `gap:22px`, `overflow:auto`. - Kicker „Aktuelle Karte" 12px/600 `#767676`, Titel = Caption der obersten Karte 28px/700 `letter-spacing:-.02em`, darunter „Name · Untertitel" 15px `#5f5f5f`. - Hairline `1px #efefef`. - **Statistik-Raster** 3 Spalten, `gap:10px`: Kachel `background:#f5f5f5`, `radius:16px`, `padding:14px`; Wert 18px/700 `tabular-nums`, Label 12px `#767676`. - **Beschreibung**: Kicker + Fließtext 15px, `line-height:1.7`, `#333333`, `text-wrap:pretty`. - **Tags**: Pills `padding:8px 14px`, `radius:18px`, `background:#efefef`, 13px/600 `#111111`. - **Aktionen unten** (`margin-top:auto`, `gap:8px`), beide `padding:14px; radius:24px; font:700 15px`: „Zur Sammlung hinzufügen" (rot `#e60023`, weiß, Hover `#ad081b`) = gleiche Aktion wie „Merken"; „Überspringen" (`#efefef`, `#111111`, Hover `#e2e2e2`) = gleiche Aktion wie ✕. ### B. Profil - `padding:32px 24px 40px`, `overflow:auto`, Einblendung `riseIn .26s`. - Kopf **zentriert** als Spalte, `gap:10px`, `padding-bottom:28px`: 120px Avatar-Kreis (`linear-gradient(140deg,#b2323c,#5d1620)`, ohne Rand), Name 36px/700 `letter-spacing:-.02em`, Meta „Studio-Konto · seit März 2026" 15px `#5f5f5f`; darunter drei Kennzahlen nebeneinander (`gap:28px`, zentriert): Posts 38, Gemerkt (live aus dem Feed), Follower 1.204 — Werte 18px/700 `tabular-nums`, Labels 13px `#767676`. - **Masonry-Raster** statt Gitter: `columns:5; column-gap:16px`. Kachel: `break-inside:avoid; margin-bottom:16px`, **unterschiedliche Höhen** (Zyklus 320 / 240 / 400 / 280 / 360 / 220 / 300 / 260 px), `radius:16px`, **kein Rahmen**, Kartenverlauf + Streifen (`opacity:.45`), `cursor:zoom-in`. Titel unten auf `linear-gradient(0deg, rgba(0,0,0,.62), transparent)`, 14px/600 weiß, `padding:14px`. **Hover:** Scrim `rgba(0,0,0,.24)` und rote Merken-Pille oben rechts (`right:12px; top:12px`, `padding:11px 16px; radius:22px`) blenden mit `.12s` ein. ### C. Erstellen - `padding:32px 24px 40px`; Inhalt in einer weißen Karte: `max-width:920px`, zentriert, `radius:24px`, `box-shadow: 0 1px 20px rgba(0,0,0,.12)`, `padding:32px`, `grid-template-columns: 1fr 320px`, `gap:32px`. - Titel „Neuen Post erstellen" 30px/700, Untertitel 15px `#5f5f5f`. - **Dropzone**: Höhe 220px, `border:2px dashed #cdcdcd`, `radius:16px`, `background:#f5f5f5`; Hover Border `#e60023`, BG `#fafafa`. Text „Dateien hierher ziehen" 16px/700 + „MP4, MOV oder bis zu 10 Bilder" 14px `#767676`. - **Felder** Titel und Untertitel: Label 13px/700 `#111111` (keine Versalien, kein `letter-spacing`); Input `padding:14px 16px`, `radius:16px`, `border:2px solid #cdcdcd`, `background:#ffffff`, Text `#111111`, 15px. Beide sind an die Live-Vorschau gebunden. - **Art**: Pills „Produkt / Video / Serie", `padding:11px 18px`, `radius:22px`, `font:700 15px`; aktiv `background:#111111`, Text `#ffffff`; inaktiv `background:#efefef`, Text `#111111`. - **Aktionen**: „Veröffentlichen" (rot `#e60023`, weiß, löst Toast „Post veröffentlicht" aus), „Als Entwurf sichern" (`#efefef`), beide `padding:14px 24px`, `radius:24px`, `font:700 15px`. - **Vorschau** (rechte Spalte): Kicker 12px/600 `#767676` + Karte 420px hoch, `radius:16px`, `linear-gradient(155deg,#1f8163,#0d4034)` + `repeating-linear-gradient(48deg, rgba(255,255,255,.07) 0 2px, transparent 2px 15px)`, unten Titel 18px/700 und Untertitel 14px auf schwarzem Verlauf — spiegelt die Eingaben live. ### D. Einstellungen - `padding:32px 24px 40px`, Inhalt `max-width:660px`, zentriert. Titel „Einstellungen" 30px/700. - Liste: Container `radius:16px`, `overflow:hidden`, `box-shadow: 0 1px 20px rgba(0,0,0,.12)`, **kein Rahmen**. Zeile `padding:20px`, `background:#ffffff`, Trenner `1px solid #efefef`; Label 16px/700, Hinweis 14px `#767676`. - Toggle: Track 52×30, `radius:999px`, kein Rahmen; aus → `background:#cdcdcd`, an → `background:#e60023`. Knopf 24px, immer `#ffffff` mit `box-shadow: 0 1px 3px rgba(0,0,0,.25)`, links 3px → 25px, Transition `left .2s cubic-bezier(.22,.9,.3,1)`. - Einträge: Videos automatisch abspielen (an), Ton beim Öffnen (aus), Wochenrückblick (an), Bewegte Übergänge (an). --- ## Interaktion & Verhalten **Karte entscheiden — vier gleichwertige Wege:** 1. **Maus-Drag**: Pointer Events auf der obersten Karte (`pointerdown` → `setPointerCapture`, `pointermove` → Delta, `pointerup`/`pointercancel` → Auswertung). Live-Transform: `translate3d(dx, dy, 0) rotate(dx/22 deg)`, Transition währenddessen aus. Schwelle **±120px**: `dx > 120` = merken, `dx < -120` = ablehnen, sonst Rücksprung (Transition wieder an). 2. **Buttons** ✕ / ↺ / „Merken" unter der Bühne (und die beiden Buttons in der Detailspalte). 3. **Merken-Pille auf der Karte** (erscheint beim Hover, oben rechts) — identisch mit „merken". 4. **Tastatur** (global, nur auf dem Feed-Screen, mit `preventDefault`): `ArrowLeft` = ablehnen, `ArrowRight` = merken, `ArrowUp` = zurücknehmen. **Hover-Zustände:** Scrim und Merken-Pille hängen am Hover der *Karte*, nicht am eigenen Element (im Prototyp `.pin:hover .pin-save` / `.pin:hover .pin-scrim`, zusätzlich `:focus-within` für Tastaturbedienung). Im Ziel-Framework als Hover-State der Kartenkomponente umsetzen — und den Fokusfall nicht vergessen, sonst ist die Pille per Tastatur nicht erreichbar. **Exit-Animation:** `transform: translate3d(±620px, -40px, 0) rotate(±22deg)`, `opacity: 0`, Dauer **320ms**, danach Index +1 und `exiting` zurücksetzen. Während `exiting` sind weitere Entscheidungen gesperrt. **Undo:** letzte Entscheidung aus der History, Index zurück, „Gemerkt"-Zähler ggf. −1. Leere History → Toast „Nichts zurückzunehmen". **Toast:** fixiert `bottom:28px`, horizontal zentriert, `padding:16px 22px`, `radius:16px`, `background:#ffffff`, `box-shadow: 0 1px 20px rgba(0,0,0,.22)`, `color:#111111`, 15px/600, Einblendung `riseIn .2s`, verschwindet nach **1700ms**. Texte: „Zu ‚' gemerkt", „Übersprungen", „Nichts zurückzunehmen", „Post veröffentlicht". **Keyframes:** - `riseIn`: `opacity:0; translateY(14px)` → `opacity:1; none` (.2–.26s ease) - `fadeIn`: `opacity:0` → `1` - Fokus: `:focus-visible { outline: 2px solid #0074e8; outline-offset: 2px; }` — nie der Browser-Default. **Responsive:** Desktop-only, `min-width:1180px`; darunter horizontal scrollen. Der Feed-Bereich scrollt bei geringer Fensterhöhe (`min-height:0; overflow:auto`). --- ## State | State | Typ | Zweck | |---|---|---| | `screen` | `'feed' \| 'profile' \| 'create' \| 'settings'` | aktive Ansicht (Icon-Rail) | | `tab` | `'videos' \| 'following' \| 'posts'` | aktiver Stapel; Wechsel setzt `idx`/`history` zurück und springt auf `feed` | | `idx` | number | Index der obersten Karte im aktuellen Stapel | | `drag` | `{x, y, active} \| null` | laufende Drag-Geste | | `exiting` | `'left' \| 'right' \| null` | laufende Exit-Animation (sperrt Eingaben) | | `history` | `{idx, dir}[]` | für Undo | | `seen`, `saved` | number | Zähler Tab-Leiste / Profil | | `showInfo` | boolean | Kürzel-Panel | | `toast` | string | Toast-Text (leer = versteckt) | | `draftTitle`, `draftSub`, `draftKind` | string | Formular „Erstellen", live in der Vorschau | | `settings` | `{autoplay, sound, digest, motion}` booleans | Einstellungen | **Datenbedarf pro Karte:** `name`, `sub`, `kind`, `assets`, `caption`, `hue: [from, to]`, `avatar` (Verlauf oder Bild-URL), `body`, `tags: string[]`, `stats: [wert, label][]`. Im Produkt ersetzt das Medium (Bild/Video) die Verlaufs-/Streifenfläche; alles andere bleibt. Die drei Tabs liefern drei Stapel (Videos, Folge ich, Posts). --- ## Design-Tokens **Farben** | Rolle | Wert | |---|---| | Seite | `#ffffff` | | Text | `#111111` | | Text gedämpft | `#5f5f5f` (Fließtext sekundär), `#767676` (Labels, inaktive Tabs), `#333333` (Beschreibung) | | Akzent (Rot) | `#e60023`, Hover `#ad081b` | | Dunkel | `#111111` (aktiver Rail-Button, aktive Art-Pille, SKIP-Badge), Hover `#000000` | | Neutrale Flächen | `#efefef` (Suchfeld, Buttons, Tags), Hover `#e2e2e2`; `#e9e9e9` (Rail-Hover); `#f5f5f5` (Kacheln, Dropzone, Leerzustand) | | Linien | `#efefef` (Trenner, Kanten), `#cdcdcd` (Eingabe-Rahmen, Toggle aus) | | Auf Medien | `rgba(255,255,255,.94)` Pills, `rgba(255,255,255,.82)` Untertitel, `rgba(0,0,0,.24)` Hover-Scrim, `rgba(0,0,0,.62)` Lesbarkeitsverlauf | | Fokus | `#0074e8` | | Karten-Verläufe | grün `#1f8163→#0d4034`, blau `#256f8b→#0c2f3f`, ocker `#8a6a2f→#3a2a11`, rot `#7a2f38→#2c1014`, tannen `#2f6f5a→#0e332b`, türkis `#1c6f7f→#0a2c33`, violett `#6a2f7a→#26102c`, gold `#7a5a2a→#2f2110` | **Typografie** — **nur Manrope** 400/500/600/700. JetBrains Mono entfällt; Zahlen laufen in Manrope mit `font-variant-numeric: tabular-nums`. Skala: 36 / 30 / 28 / 20 / 18 / 17 / 16 / 15 / 14 / 13 / 12 px. Große Überschriften `letter-spacing:-.02em`. Keine Versalien-Kicker mehr — Kicker sind 12px/600 in `#767676`, normal geschrieben. **Abstände** 2 / 4 / 6 / 8 / 10 / 12 / 14 / 16 / 18 / 20 / 22 / 24 / 26 / 28 / 30 / 32 / 40 px. **Radien** 16px (Karten, Kacheln, Eingaben, Pills auf Medien, Toast, Panel), 18 / 22 / 24 / 28px (Tag-, Art-, Button-Pillen), `50%` Kreise, `999px` Toggle-Track. **Schatten** `0 1px 20px rgba(0,0,0,.12)` Flächen/Listen · `.16` Kürzel-Panel · `.18` Karte · `.22` Toast · `0 1px 3px rgba(0,0,0,.25)` Toggle-Knopf. **Kein `backdrop-filter`** — die Pinterest-Oberfläche ist deckend. **Transitions** `.12s ease` (Hover, Farbwechsel, Ein-/Ausblenden), `.16s` (Badge), `.2s` (Toggle), Karten-Bewegung `.34s cubic-bezier(.22,.9,.3,1)`, Exit `320ms`. --- ## Assets Keine Binärdateien im Prototyp. Alle Medien sind Platzhalter aus CSS-Verläufen und Streifenmustern — im Produkt durch echte Bilder/Videos ersetzen. Icons: **Lucide** (im Prototyp Unicode-Glyphen als Platzhalter). Fonts: Google Fonts — **nur Manrope**. ## Offene Punkte - **Suchfeld ohne Funktion.** Die Pinterest-Kopfzeile lebt von der Suche, im Prototyp ist sie eine reine Attrappe — es gibt bisher keine Suchfunktion in der App. Vor der Umsetzung klären, ob Suche gebaut wird; wenn nicht, gehört das Feld raus, statt eine Funktion vorzutäuschen. - **Pinterest-Referenz liegt nicht im Repo.** Die Vorlage kam als Screenshot im Chat. Wer sie dauerhaft braucht, legt sie als `referenz/pinterest-desktop.png` daneben. ## Dateien in diesem Bundle - `PROMPT.md` — fertiger Auftrag zum Einfügen in Claude Code. - `Videogen Web.dc.html` — der Prototyp (Template oben, Logikklasse mit Zustand/Interaktion unten, Beispieldaten in `DATA`). - `support.js` — Laufzeit, damit die HTML-Datei sich lokal öffnen lässt. Nicht portieren. - `README.md` — dieses Dokument. - `referenz/mobile-ansicht-im-browser.png` — Ausgangslage: die Mobile-App als schmale Spalte unter `videogen.project.webklar.com`, die diese Desktop-Adaption ersetzt.