Noder som dras inn i skjermen rendres uten grensesnittelementer — ingen BlockShell-header, border, resize-handles. Bare rent innhold. Skjermen er output, ikke utviklerverktøy. Vert redigerer layout via skjermens egen editor-modus. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
286 lines
8.9 KiB
Markdown
286 lines
8.9 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 **uten grensesnittelementer**.
|
|
Ingen BlockShell-header, ingen resize-handles, ingen border, ingen
|
|
skygge. Bare innholdet. Skjermen er output — den skal se ut som
|
|
et ferdig bilde, ikke som et utviklerverktøy.
|
|
|
|
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:**
|
|
```
|
|
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
|