synops/docs/proposals/skjermen.md
vegard c9bee967c7 Skjermen: dedikert sceneskifte-knapp med 0.2s fade + auto-pause
Én knapp, to trykk: fade ut (0.2s) → pause → bygg om → trykk igjen
→ fade inn (0.2s). Kort default for praktisk bruk, konfigurerbar.
Master opacity slider er separat for kreativ/manuell kontroll.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 08:15:11 +00:00

370 lines
12 KiB
Markdown

# Proposal: Skjermen — live-produksjon i arbeidsflaten
## Konsept
"Skjermen" er et panel i arbeidsflaten som fungerer som et
produksjonsbord. Du drar inn videostrømmer, bilder, tekst og
andre noder — og arrangerer dem fritt. Det som er i skjermen
er det som tas opp eller strømmes.
Skjermen er ikke en video-editor. Den er en **live kompositor**
som bruker drag-and-drop med eksisterende noder.
## Delt arbeidsflate som møterom/studio
Et møterom eller studio er en delt arbeidsflate med riktige traits.
Alle deltakere ser sin egen arbeidsflate, men skjermen(e) er
synkronisert — alle ser samme komposisjon.
```
Delt arbeidsflate (podcaststudio):
Synkronisert: Personlig:
┌──────────────────────┐ ┌─────────┐
│ SKJERM (program) │ │ Notater │ ← kun deg
│ Trond │ Arne │ └─────────┘
│ Vegard│ Logo │ ┌─────────┐
│ ●REC │ │ Chat │ ← alle ser
└──────────────────────┘ └─────────┘
┌──────────────────────┐ ┌─────────┐
│ SKJERM (preview) │ │ Mixer │ ← delt
│ Arne (stor) │ └─────────┘
│ Trond│Vegard (små) │
└──────────────────────┘
```
## Videoramme
Hvert deltaker har et panel — "videoramme" — som fanger kamera
og mikrofon. Produserer en LiveKit-track som er en strøm-node.
- Styres av eieren (velg kamera, mikrofon, on/off)
- Kan dras inn i skjermer av vert/produsent
- Samme strøm kan refereres fra flere skjermer
- Kan også fange skjermdeling
## Skjerm-panelet
### Grunnfunksjoner
- **Drop-target:** aksepterer videostrømmer, bilder, tekst, noder
- **Fritt arrangement:** hvert element har posisjon, størrelse, z-order
- **Resizerbart:** elementene inne i skjermen resizes fritt
- **Aspect ratio:** låses til 16:9 (default), 4:3, 1:1 eller fritt
- **Bakgrunn:** farge, gradient eller bilde
- **Snap-to-grid:** valgfritt, for presis plassering
### Frameless modus
Noder som dras inn i skjermen rendres **som standard uten
grensesnittelementer** — ingen BlockShell-header, ingen resize-handles,
ingen border, ingen skygge. Bare innholdet. Skjermen er output.
Frameless er default, men **valgfritt per element**. Vert kan slå
på ramme, navneskilt, skygge eller andre visuelle effekter per
element i skjermen. Nyttig for f.eks. et bilde med border, eller
en videostrøm med semi-transparent navnebanner over.
Resize og flytting av elementer *inne i skjermen* gjøres av
skjermens egen editor-modus (kun tilgjengelig for vert), ikke
av BlockShell. Elementene er rene rektangler med innhold.
Dette betyr at noder trenger en `frameless`-renderingsmodus:
- **Videoramme:** bare `<video>` — ingen kontroller, ingen header
- **Bildenode:** bare `<img>` — ingen border, ingen metadata
- **Tekstnode:** bare teksten — med font/farge/størrelse
- **Chat-overlay:** bare meldingsstrøm — transparent bakgrunn
BlockShell brukes fortsatt for paneler *utenfor* skjermen
(i arbeidsflaten). Det er bare inne i skjerm-panelet at
innhold rendres frameless.
### Ting som kan dras inn
| Kilde | Resultat i skjermen |
|-------|---------------------|
| Videoramme (deltaker) | Ren video-strøm (frameless) |
| Bildenode (CAS) | Rent bilde (frameless) |
| Tekstnode | Ren tekst med styling (frameless) |
| Chat-panel | Meldingsstrøm med transparent bg |
| Lydvisualisering | Waveform/VU uten ramme |
| Presentasjon | Slides (frameless) |
| Skjermdeling | Deltakerens skjerm (frameless) |
| Annen node | Minimal rendering, tilpasset innhold |
### Fade og overganger
**Master opacity slider:**
- 0% (helt svart) til 100% (fullt synlig)
- Live, sanntids — brukes som manuell fade
**Sceneskifte-knapp (dedikert, godt synlig):**
Én knapp. To trykk. Ferdig.
```
Trykk 1: "Sceneskifte"
→ Rask fade til svart (0.2s default, konfigurerbar)
→ Opptak pauses automatisk ved full blackout
→ Knappen endrer tekst/farge: "Fortsett" (pulserer)
→ Bygg om scenen i ro og mak
Trykk 2: "Fortsett"
→ Opptak resumer
→ Rask fade inn fra svart (0.2s)
→ Knappen tilbake til "Sceneskifte"
```
I opptaksfilen: ...scene A [0.2s fade] scene B...
Ser ut som en profesjonell overgang. Pausen er usynlig.
Fade-varigheten er kort som default (0.2s) — dette er et
praktisk verktøy for å bytte scene raskt, ikke en kunstnerisk
overgang. Kan justeres i innstillinger om ønskelig.
**Master opacity slider (separat):**
- For manuell kontroll / kreativ bruk
- 0-100%, live
- Uavhengig av sceneskifte-knappen
**Overgangstyper (for multi-skjerm switching):**
- Fade til svart (default)
- Fade til hvitt
- Fade til egendefinert farge
- Crossfade (mellom to skjermer — se multi-skjerm)
- Cut (øyeblikkelig, ingen fade)
### Opptak
- **REC-knapp** (rød prikk, synlig i skjerm-headeren)
- **Pause/resume** (usynlig i output, sømløst)
- **Tidskode-display** (total innspilt tid)
- **Markører:** klikk for å sette en markør ("dette var bra",
"klipp her") som lagres som tidsstempel-metadata
- **Output:** server-side compositing via FFmpeg, eller
canvas-capture API for klientsiden
### Forhåndsdefinerte layouts
Hurtigknapper for vanlige oppsett:
- **Fullskjerm:** én kilde fyller alt
- **2-split:** to kilder side om side
- **3-split:** tre kilder (1 stor + 2 små, eller 3 like)
- **PiP:** én stor + én liten i hjørnet
- **Grid:** 2x2 eller 3x3
- Alltid mulig å justere manuelt etterpå
## Multi-skjerm: Program / Preview
### Konsept
To (eller flere) skjermer som fungerer som TV-studio:
- **Program:** det som tas opp/strømmes akkurat nå
- **Preview:** neste scene du forbereder
Samme videostrøm kan ligge i begge, med ulik layout.
"Take" bytter dem.
### Bytte mellom skjermer
**Cut (øyeblikkelig):**
- Preview → Program, Program → Preview
- Bytte skjer på én frame
**Take (med overgang):**
- Crossfade mellom Program og Preview
- Konfigurerbar varighet
- Program og Preview bytter roller etter overgangen
**Manuelt:**
- Velg hvilken skjerm som er "live" via knapp/dropdown
- De andre er tilgjengelige for redigering
### Brukseksempel: podcast med kameraveksling
```
Skjerm A (program): Alle tre i grid
Skjerm B (preview): Arne stor, Trond+Vegard små
Arne snakker → produsent trykker "Take" →
Crossfade til Skjerm B (Arne stor) →
Skjerm A er nå preview, redigeres for neste bytte
Trond tar over → produsent bygger Skjerm A om:
Trond stor, Arne+Vegard små →
Trykker "Take" → crossfade til Skjerm A
```
Alt live, under innspilling, uten klipping etterpå.
### Ubegrenset antall skjermer
Ikke begrenset til to. Du kan ha:
- Skjerm A: alle i grid (oversikt)
- Skjerm B: Arne stor (nærportrett)
- Skjerm C: Trond stor
- Skjerm D: Vegard stor
- Skjerm E: presentasjon fullskjerm
- Skjerm F: chat-overlay over video
Bytt mellom dem etter behov. Hver har sin egen layout
men deler de samme kilde-strømmene.
## Teknisk modell
### Skjerm som node
```
node_kind: 'screen'
metadata: {
aspect_ratio: '16:9',
background: { type: 'color', value: '#000000' },
elements: [
{ node_id: '<tronds-video>', x: 0, y: 0, w: 50, h: 50, z: 1 },
{ node_id: '<arnes-video>', x: 50, y: 0, w: 50, h: 50, z: 1 },
{ node_id: '<logo>', x: 80, y: 80, w: 15, h: 15, z: 10 },
],
is_program: true, // denne skjermen tas opp
}
```
Posisjon/størrelse i prosent (0-100) for oppløsningsuavhengighet.
### Skjerm i arbeidsflaten
Skjermen er et BlockShell-panel som:
- Viser intern canvas med elementene
- Synkroniseres via PG NOTIFY (alle ser samme layout)
- Kun `owner`/`admin` kan endre innhold (dra inn/ut, resize)
- Deltakere ser resultatet i sanntid
### Opptak
**Klientside (enklest):**
- Canvas-capture API → MediaRecorder → upload til CAS
- Begrensning: kvalitet avhenger av klientens maskin
**Serverside (bedre):**
- Maskinrommet mottar layout-metadata + LiveKit-strømmene
- FFmpeg compositor renderer til fil i sanntid
- Uavhengig av klientens ytelse
- Kan produsere flere oppløsninger
**Hybrid:**
- Klientside for preview/monitoring
- Serverside for endelig opptak
### Overgangsmotor
```rust
struct Transition {
from_screen: NodeId,
to_screen: NodeId,
kind: TransitionKind, // Fade, Cut, Crossfade, DipToColor
duration_ms: u32,
color: Option<Color>, // for DipToColor
}
```
Ved sceneskifte med pause:
```
1. Start DipToColor(svart) overgang
2. Ved midtpunkt (100% svart): emit PauseRecording
3. Vent på ResumeRecording signal
4. Fullfør DipToColor (svart → transparent)
```
## Hva dette bygger på (eksisterende)
- BlockShell: panel-wrapper med resize, drag, drop
- Canvas: spatial layout med pan/zoom
- LiveKit: WebRTC for video/lyd-strømmer
- Drag-and-drop: universell overføring mellom paneler
- CAS: lagring av opptak og bilder
- PG NOTIFY + WebSocket: synkronisering av skjerm-layout
- Node/edge-modell: alt er noder med relasjoner
## Hva som er nytt
- Skjerm-panel (canvas-i-canvas) med elementliste
- Videoramme-panel (kamera/mikrofon-fangst)
- Fade/overgang-motor
- Multi-skjerm switching (program/preview)
- Server-side compositing (FFmpeg)
- Opptak med pause/resume og markører
## Ytelsesanalyse (mars 2026)
### Serverspesifikasjoner
- 8 kjerner AMD EPYC @ 2.4 GHz (ingen hyperthreading)
- 16 GB RAM (~10 GB tilgjengelig)
- 204 GB ledig disk
- ~270 Mbit/s båndbredde (Hetzner)
- Ingen GPU
### Video-strømmer (LiveKit SFU)
LiveKit er en SFU (Selective Forwarding Unit) — den videresender
strømmer uten transkoding. Minimal CPU, primært båndbredde.
- 3 deltakere: 9 strømmer (3 inn + 6 ut), ~15-25 Mbit/s
- 10 deltakere: 100 strømmer, ~150-250 Mbit/s uten simulcast
- 10 deltakere med simulcast: ~80-120 Mbit/s (realistisk)
- LiveKit RAM: ~50-100 MB per sesjon med 3 deltakere
### Server-side compositing (FFmpeg)
FFmpeg compositor: flere video-strømmer → én output.
- 3 strømmer @ 720p → 1080p: ~2-3 CPU-kjerner kontinuerlig
- RAM: ~500 MB - 1 GB per FFmpeg-instans
### Kapasitetstabell
| Scenario | Gjennomførbart? | Flaskehals |
|----------|----------------|------------|
| 3 deltakere, klientside opptak | ✅ Enkelt | Ingen |
| 3 deltakere, server compositing | ✅ Ja | 2-3 CPU-kjerner |
| 10 deltakere, klientside | ✅ Ja (med simulcast) | Båndbredde |
| 10 deltakere, server compositing | ⚠️ Grenseland | CPU + båndbredde |
| 3 samtidige team, klientside | ✅ Ja | LiveKit RAM |
| 3 samtidige team, server comp. | ❌ Nei | CPU (trenger 6-9 kjerner) |
| 3 team klient + 1 team server | ✅ Ja | Balansert |
### Strategi
**Klientside compositing som default.** Skjerm-panelet bruker
Canvas API til å komponere video-strømmene i nettleseren.
Opptak via MediaRecorder API. Serveren bare videresender strømmer.
Fordeler:
- Serveren belastes minimalt — skalerer til mange samtidige team
- Null ekstra CPU for compositing
- Lavere latens (ingen round-trip til server)
Ulemper:
- Opptak-kvalitet avhenger av klientens maskin
- Klienten må ha nok CPU (moderne laptop/desktop er nok)
**Server-side compositing som valgfri premium:**
- For opptak i høyere kvalitet enn klienten klarer
- For eksport/re-rendering i etterkant
- Begrenset til én sesjon om gangen på nåværende server
- Købasert: "bestill rendering" → jobbkø → ferdig → varsling
**Oppgradering ved behov:**
- 16-kjerner, 32 GB hos Hetzner: ~€30/mnd ekstra
- Gir kapasitet for 2-3 samtidige server-side compositinger
- Eller: dedikert render-server (billig Hetzner-boks kun for FFmpeg)
## Prioritet
Høy ambisjon, kan bygges inkrementelt:
1. Videoramme-panel (LiveKit-kamera i BlockShell)
2. Enkel skjerm (drop-target med elementer, statisk layout)
3. Opptak (klientside canvas-capture)
4. Fade/overgang
5. Multi-skjerm switching
6. Server-side compositing
7. Sceneskifte med auto-pause