Phase 12: frame-accurate timecode via an overscan band — vgstrip encoder/decoder, sweep writes tmcd + creation_time + sidecar, dumpd /time, Caddy /time routes, MediaMTX microsecond names, /dock/clock/ page, dock band setup via obs-websocket, Go Live band composite + toggle, portal crops the band
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -9,6 +9,7 @@ export default function Player({ params, api }) {
|
||||
const videoRef = useRef(null)
|
||||
const [status, setStatus] = useState('connecting…')
|
||||
const [viewers, setViewers] = useState(params.viewers ?? 0)
|
||||
const [aspect, setAspect] = useState(null) // game aspect once we know the video size (crops the timecode band)
|
||||
const state = audio.use()
|
||||
const muted = effectiveMuted(state, id)
|
||||
const volume = state.streams[id]?.volume ?? 0.8
|
||||
@@ -72,7 +73,13 @@ export default function Player({ params, api }) {
|
||||
const icon = muted ? '🔇' : volume === 0 ? '🔈' : volume < 0.5 ? '🔉' : '🔊'
|
||||
return (
|
||||
<div className={'player' + (focused ? ' focused' : '')} onMouseDown={() => api.setActive?.()}>
|
||||
<video ref={videoRef} autoPlay playsInline muted />
|
||||
<div className="vwrap" style={aspect ? { aspectRatio: aspect } : undefined}>
|
||||
<video ref={videoRef} autoPlay playsInline muted className={aspect ? 'cropband' : ''}
|
||||
onLoadedMetadata={e => { const v = e.currentTarget; const w = v.videoWidth, h = v.videoHeight; if (!w || !h) return
|
||||
let band = Math.round(w / 160); band += band % 2; const gameH = h - band
|
||||
// only treat it as a band if the remaining height is a standard game height
|
||||
setAspect([720, 1080, 1440, 2160].includes(gameH) ? `${w} / ${gameH}` : null) }} />
|
||||
</div>
|
||||
{status && <div className="status">{status}</div>}
|
||||
<div className="bar">
|
||||
<span className="live">LIVE</span>
|
||||
|
||||
Reference in New Issue
Block a user