Proposal: Skjermen — live-produksjon i arbeidsflaten
Skjerm-panel som live kompositor: dra inn videostrømmer, bilder, tekst og noder. Multi-skjerm med program/preview og live switching. Sceneskifte med fade-to-black + auto-pause for jukseredigering. Videoramme per deltaker, delt arbeidsflate som møterom/studio. Bygger på eksisterende primitiver (BlockShell, Canvas, LiveKit, drag-and-drop, CAS, PG NOTIFY). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
2605f6de25
commit
af17ee3fa4
1 changed files with 265 additions and 0 deletions
265
docs/proposals/skjermen.md
Normal file
265
docs/proposals/skjermen.md
Normal file
|
|
@ -0,0 +1,265 @@
|
||||||
|
# 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
|
||||||
|
|
||||||
|
### Ting som kan dras inn
|
||||||
|
|
||||||
|
| Kilde | Resultat i skjermen |
|
||||||
|
|-------|---------------------|
|
||||||
|
| Videoramme (deltaker) | Live video-strøm |
|
||||||
|
| Bildenode (CAS) | Statisk bilde (logo, illustrasjon) |
|
||||||
|
| Tekstnode | Tittel, banner, navn-skilt |
|
||||||
|
| Chat-panel | Live chat-overlay |
|
||||||
|
| Lydvisualisering | Waveform/VU som visuelt element |
|
||||||
|
| Presentasjon | Slides (bla manuelt eller auto) |
|
||||||
|
| Skjermdeling | Deltakerens skjerm som strøm |
|
||||||
|
| Annen node | Rendres som kort/boks |
|
||||||
|
|
||||||
|
### Fade og overganger
|
||||||
|
|
||||||
|
**Master opacity slider:**
|
||||||
|
- 0% (helt svart) til 100% (fullt synlig)
|
||||||
|
- Live, sanntids — brukes som manuell fade
|
||||||
|
|
||||||
|
**Sceneskifte-knapp:**
|
||||||
|
```
|
||||||
|
1. Trykk "Sceneskifte"
|
||||||
|
2. Fade ut til svart (0.5-3s, konfigurerbar)
|
||||||
|
3. Opptak pauses automatisk ved full blackout
|
||||||
|
4. Bygg om scenen bak svartsensuren (flytt, resize, legg til, fjern)
|
||||||
|
5. Trykk "Sceneskifte" igjen (eller "Fortsett")
|
||||||
|
6. Opptak resumer
|
||||||
|
7. Fade inn fra svart (samme varighet)
|
||||||
|
```
|
||||||
|
|
||||||
|
I opptaksfilen ser det ut som én jevn overgang. Ingen klipping
|
||||||
|
nødvendig. Live jukseredigering.
|
||||||
|
|
||||||
|
**Overgangstyper:**
|
||||||
|
- Fade til svart (default)
|
||||||
|
- Fade til hvitt
|
||||||
|
- Fade til egendefinert farge
|
||||||
|
- Crossfade (mellom to skjermer — se multi-skjerm)
|
||||||
|
|
||||||
|
### 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
|
||||||
|
|
||||||
|
## 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
|
||||||
Loading…
Add table
Reference in a new issue