webapp: archive pre-migration scene dirs + bash scripts, update docs
Moves the seven HTML scene dirs (landing/, loading/, game/, desktop/,
goodbye/, music-box/, music/) and the superseded bash helpers (setup.sh,
loading.sh, playlist.sh, telemetry.sh) into archived/ rather than deleting.
The Laravel webapp/ replaces all of them; archived/README.md spells out
the rollback procedure.
Also:
- rewrite the relevant sections of CLAUDE.md so it points at webapp/
blade views, the Artisan commands, and the supervisord lifecycle
(`supervisorctl restart obs-webapp` after route / controller / .env
changes; Blade view edits are still safe-while-running via OBS's
Refresh cache).
- extend scripts/deploy-rig.sh to install php + composer + supervisor,
run `composer install`, copy obs-webapp.supervisord.conf into
/etc/supervisor.d/, start the program, and call `php artisan
rig:setup` + `rig:telemetry --collect` instead of the old bash.
- .gitignore catches the generated machine-local files that came along
when the old scene dirs moved (telemetry.js, loading.json, playlist.js,
cmd.js, obs-config.js).
- daemon.blade.php is now passive — listens to mpd:state but does not
play audio or broadcast its own queue, so it stops fighting with
bridges/mpd-state.py (the post-browser-daemon-migration source of
truth for mpd:state).
- nc.blade.php overrides .terminal { overflow: hidden } from hud.css
so the `┤ TERMINAL ├` and `┤ NOW PLAYING ├` pane-tabs stick above
the pane border instead of being clipped.
This commit is contained in:
486
archived/scenes/landing/index.html
Normal file
486
archived/scenes/landing/index.html
Normal file
@@ -0,0 +1,486 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>OPHI-118 / STAND BY</title>
|
||||
<style>
|
||||
:root {
|
||||
--bg: #07080d;
|
||||
--ink: #e8e8e0;
|
||||
--hud: #4fd2ff;
|
||||
--hud-dim: #2a7fa6;
|
||||
--accent: #e63a2e;
|
||||
--warn: #ffd000;
|
||||
--mono: 'DejaVu Sans Mono', 'Liberation Mono', 'Consolas', monospace;
|
||||
--display: 'DejaVu Sans', 'Liberation Sans', 'Helvetica', 'Arial', sans-serif;
|
||||
}
|
||||
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
|
||||
html, body {
|
||||
width: 100%; height: 100%;
|
||||
background: var(--bg);
|
||||
color: var(--ink);
|
||||
font-family: var(--display);
|
||||
overflow: hidden;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
body {
|
||||
position: relative;
|
||||
display: grid;
|
||||
grid-template-rows: auto 1fr auto auto;
|
||||
padding: 40px 72px;
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
/* ───────── HUD top strip ───────── */
|
||||
.hud {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
align-items: center;
|
||||
font-family: var(--mono);
|
||||
font-size: 22px;
|
||||
font-weight: 700;
|
||||
color: var(--hud);
|
||||
letter-spacing: 0.08em;
|
||||
}
|
||||
.hud .group { display: flex; gap: 28px; align-items: center; }
|
||||
.hud > .group:nth-child(1) { justify-self: start; }
|
||||
.hud > .group:nth-child(2) { justify-self: center; }
|
||||
.hud > .group:nth-child(3) { justify-self: end; }
|
||||
.hud .dim { color: var(--hud-dim); }
|
||||
.hud .group > span { display: inline-flex; align-items: center; gap: 12px; }
|
||||
|
||||
/* "OPHI-118 // <RIG>" station identifier. The rig portion gets a subtle
|
||||
monochrome glitch — character scramble that resolves back to the real
|
||||
name every ~9s. CSS-only flicker; the scramble itself is in JS. */
|
||||
.station {
|
||||
display: inline-flex;
|
||||
align-items: baseline;
|
||||
gap: 0;
|
||||
white-space: pre; /* preserve the " // " spacing as-is */
|
||||
}
|
||||
.station .sep { color: var(--hud-dim); margin: 0 0.45em; letter-spacing: 0.32em; }
|
||||
.station .rig {
|
||||
display: inline-block;
|
||||
color: var(--hud);
|
||||
text-shadow: 0 0 10px rgba(79, 210, 255, 0.55);
|
||||
font-variant-numeric: tabular-nums;
|
||||
/* Subtle width-stable bracket dimming. The brackets sit just outside the
|
||||
name so the scramble glyphs (which can be wider than 1ch in mono) don't
|
||||
visually push the layout around. */
|
||||
}
|
||||
.station .rig::before,
|
||||
.station .rig::after {
|
||||
color: var(--hud-dim);
|
||||
font-weight: 700;
|
||||
text-shadow: none;
|
||||
}
|
||||
.station .rig::before { content: '['; margin-right: 0.32em; }
|
||||
.station .rig::after { content: ']'; margin-left: 0.32em; }
|
||||
.station .rig.glitching {
|
||||
color: var(--warn);
|
||||
text-shadow: 0 0 12px rgba(255, 208, 0, 0.5);
|
||||
}
|
||||
.hud .led {
|
||||
display: inline-block;
|
||||
width: 11px; height: 11px;
|
||||
border-radius: 50%;
|
||||
background: var(--accent);
|
||||
box-shadow: 0 0 10px var(--accent);
|
||||
/* Small upward nudge: flex centers on line-box mid, but caps-only text
|
||||
reads centered around cap-height mid which sits a touch higher. */
|
||||
margin-top: -0.08em;
|
||||
animation: rec-blink 1.6s ease-in-out infinite;
|
||||
}
|
||||
/* The ▮/▯ glyphs in DejaVu Sans Mono are designed centered on x-height,
|
||||
not cap-height, so against all-caps SIGNAL their visual middle sits low.
|
||||
Lift by ~(cap-mid − x-mid) ≈ 0.10em to put the glyph center on cap center. */
|
||||
#signal {
|
||||
display: inline-block;
|
||||
transform: translateY(-0.10em);
|
||||
}
|
||||
@keyframes rec-blink {
|
||||
0%, 55% { opacity: 1; }
|
||||
65%, 100% { opacity: 0.2; }
|
||||
}
|
||||
|
||||
/* ───────── Centered mark ───────── */
|
||||
.stage {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 36px;
|
||||
}
|
||||
.mark {
|
||||
width: 360px; height: 360px;
|
||||
/* Static glow only — animated drop-shadow is CPU-expensive in CEF.
|
||||
The static breathing feel comes from the rec-blink LED + cd-pulse
|
||||
elsewhere; the mark just has a steady halo. */
|
||||
filter: drop-shadow(0 0 22px rgba(58, 209, 255, 0.35));
|
||||
}
|
||||
.bars {
|
||||
display: flex;
|
||||
width: 720px;
|
||||
height: 14px;
|
||||
opacity: 0.32;
|
||||
}
|
||||
.bars i { flex: 1; display: block; }
|
||||
.bars i:nth-child(1) { background: #c7c7c7; }
|
||||
.bars i:nth-child(2) { background: #c7c700; }
|
||||
.bars i:nth-child(3) { background: #00c7c7; }
|
||||
.bars i:nth-child(4) { background: #00c700; }
|
||||
.bars i:nth-child(5) { background: #c700c7; }
|
||||
.bars i:nth-child(6) { background: #c70000; }
|
||||
.bars i:nth-child(7) { background: #0000c7; }
|
||||
|
||||
/* ───────── Standby block ───────── */
|
||||
.standby {
|
||||
text-align: center;
|
||||
}
|
||||
.standby .big {
|
||||
font-size: 130px;
|
||||
font-weight: 900;
|
||||
letter-spacing: 0.20em;
|
||||
line-height: 1;
|
||||
text-shadow: 0 0 18px rgba(79, 210, 255, 0.18);
|
||||
animation: standby-pulse 3s ease-in-out infinite;
|
||||
}
|
||||
.standby .sub {
|
||||
margin-top: 30px;
|
||||
font-family: var(--mono);
|
||||
font-size: 26px;
|
||||
letter-spacing: 0.45em;
|
||||
color: var(--hud-dim);
|
||||
}
|
||||
@keyframes standby-pulse {
|
||||
0%, 100% { opacity: 0.90; }
|
||||
50% { opacity: 1.00; }
|
||||
}
|
||||
|
||||
/* ───────── Bottom HUD ───────── */
|
||||
.foot {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-family: var(--mono);
|
||||
font-size: 19px;
|
||||
color: var(--hud-dim);
|
||||
letter-spacing: 0.12em;
|
||||
}
|
||||
.foot .warn { color: var(--warn); }
|
||||
/* Mirrors .station .rig.glitching — bottom telemetry uses the same scramble
|
||||
reveal as the top rig identifier, so it shares the warn-yellow tint. */
|
||||
#rig.glitching {
|
||||
color: var(--warn);
|
||||
text-shadow: 0 0 10px rgba(255, 208, 0, 0.4);
|
||||
}
|
||||
|
||||
/* ───────── Overlays ───────── */
|
||||
#static {
|
||||
position: absolute; inset: 0;
|
||||
width: 100%; height: 100%;
|
||||
pointer-events: none;
|
||||
opacity: 0.045;
|
||||
mix-blend-mode: screen;
|
||||
image-rendering: pixelated;
|
||||
}
|
||||
.scanlines {
|
||||
position: absolute; inset: 0;
|
||||
pointer-events: none;
|
||||
background: repeating-linear-gradient(
|
||||
to bottom,
|
||||
rgba(0,0,0,0) 0px,
|
||||
rgba(0,0,0,0) 2px,
|
||||
rgba(0,0,0,0.20) 3px,
|
||||
rgba(0,0,0,0.20) 4px
|
||||
);
|
||||
opacity: 0.5;
|
||||
mix-blend-mode: multiply;
|
||||
}
|
||||
.vignette {
|
||||
position: absolute; inset: 0;
|
||||
pointer-events: none;
|
||||
background: radial-gradient(
|
||||
ellipse at center,
|
||||
rgba(0,0,0,0) 45%,
|
||||
rgba(0,0,0,0.60) 100%
|
||||
);
|
||||
}
|
||||
.flicker {
|
||||
position: absolute; inset: 0;
|
||||
pointer-events: none;
|
||||
background: rgba(0,0,0,0);
|
||||
animation: flicker 11s ease-in-out infinite;
|
||||
}
|
||||
@keyframes flicker {
|
||||
0%, 100% { background: rgba(0,0,0,0); }
|
||||
18% { background: rgba(0,0,0,0); }
|
||||
18.3% { background: rgba(0,0,0,0.06); }
|
||||
18.5% { background: rgba(0,0,0,0); }
|
||||
47% { background: rgba(0,0,0,0); }
|
||||
47.3% { background: rgba(0,0,0,0.08); }
|
||||
47.5% { background: rgba(0,0,0,0); }
|
||||
78% { background: rgba(0,0,0,0); }
|
||||
78.4% { background: rgba(0,0,0,0.05); }
|
||||
78.7% { background: rgba(0,0,0,0); }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<header class="hud">
|
||||
<div class="group">
|
||||
<span><span class="led"></span>TRANSMISSION</span>
|
||||
<span class="station">
|
||||
<span class="station-id">OPHI-118</span>
|
||||
<span class="sep">//</span>
|
||||
<span class="rig" id="rigName">--</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="group">
|
||||
<span class="dim">SIGNAL</span>
|
||||
<span id="signal">▮▮▮▯▯</span>
|
||||
</div>
|
||||
<div class="group">
|
||||
<span class="dim">UTC</span>
|
||||
<span id="clock">--:--:--</span>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="stage">
|
||||
<svg class="mark" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="100" cy="100" r="92" fill="none" stroke="#3ad1ff" stroke-width="1.2" opacity="0.35"/>
|
||||
<circle cx="100" cy="100" r="80" fill="none" stroke="#3ad1ff" stroke-width="2.5"/>
|
||||
<g stroke="#3ad1ff" stroke-width="2" opacity="0.55">
|
||||
<line x1="100" y1="8" x2="100" y2="22"/>
|
||||
<line x1="100" y1="178" x2="100" y2="192"/>
|
||||
<line x1="8" y1="100" x2="22" y2="100"/>
|
||||
<line x1="178" y1="100" x2="192" y2="100"/>
|
||||
</g>
|
||||
<polygon points="100,52 148,140 52,140"
|
||||
fill="none" stroke="#e63a2e" stroke-width="3.5" stroke-linejoin="miter"/>
|
||||
<circle cx="100" cy="116" r="4" fill="#ffd000"/>
|
||||
</svg>
|
||||
<div class="bars"><i></i><i></i><i></i><i></i><i></i><i></i><i></i></div>
|
||||
</main>
|
||||
|
||||
<section class="standby">
|
||||
<div class="big">PLEASE STAND BY</div>
|
||||
<div class="sub">— DO NOT ADJUST YOUR RECEIVER —</div>
|
||||
</section>
|
||||
|
||||
<footer class="foot">
|
||||
<span>CH 118.0 MHz</span>
|
||||
<span id="rig">— TELEMETRY —</span>
|
||||
<span class="warn">▲ AUDIO ACTIVE</span>
|
||||
</footer>
|
||||
|
||||
<canvas id="static"></canvas>
|
||||
<div class="scanlines"></div>
|
||||
<div class="vignette"></div>
|
||||
<div class="flicker"></div>
|
||||
|
||||
<!-- Static device specs as a global. Generated by telemetry.sh.
|
||||
Loaded via <script> instead of fetch() because OBS's CEF blocks
|
||||
file:// → file:// fetch (Chromium "unique origin" rule). -->
|
||||
<script src="telemetry.js"></script>
|
||||
|
||||
<script>
|
||||
// Live UTC clock
|
||||
const clockEl = document.getElementById('clock');
|
||||
const pad = n => String(n).padStart(2, '0');
|
||||
const tickClock = () => {
|
||||
const d = new Date();
|
||||
clockEl.textContent = `${pad(d.getUTCHours())}:${pad(d.getUTCMinutes())}:${pad(d.getUTCSeconds())}`;
|
||||
};
|
||||
tickClock();
|
||||
setInterval(tickClock, 1000);
|
||||
|
||||
// Signal bar fluctuation — 3 bars typical, occasional drop or spike
|
||||
const sigEl = document.getElementById('signal');
|
||||
const FILL = '▮', EMPTY = '▯';
|
||||
const drawSig = n => FILL.repeat(n) + EMPTY.repeat(5 - n);
|
||||
setInterval(() => {
|
||||
const r = Math.random();
|
||||
const n = r < 0.06 ? 2 : r < 0.70 ? 3 : r < 0.95 ? 4 : 5;
|
||||
sigEl.textContent = drawSig(n);
|
||||
}, 1500);
|
||||
|
||||
// Animated CRT static (small buffer, scaled by browser)
|
||||
const cv = document.getElementById('static');
|
||||
const ctx = cv.getContext('2d');
|
||||
const W = 320, H = 180;
|
||||
cv.width = W; cv.height = H;
|
||||
const img = ctx.createImageData(W, H);
|
||||
const drawNoise = () => {
|
||||
const d = img.data;
|
||||
for (let i = 0; i < d.length; i += 4) {
|
||||
const v = (Math.random() * 255) | 0;
|
||||
d[i] = d[i+1] = d[i+2] = v;
|
||||
d[i+3] = 255;
|
||||
}
|
||||
ctx.putImageData(img, 0, 0);
|
||||
};
|
||||
drawNoise();
|
||||
// 8 fps — visually almost identical to 12 fps but ~33% less paint work.
|
||||
setInterval(drawNoise, 1000 / 8);
|
||||
|
||||
// ───────── Cyberpunk decode/scramble reveal ─────────
|
||||
// Each call: replace target text with random glyphs for `scrambleMs`, then
|
||||
// resolve to `finalText` left-to-right. Same effect family as the cyberpunk
|
||||
// "decoder" trope; pairs with the CRT aesthetic rather than fighting it.
|
||||
// Used by both the top rig identifier and the bottom telemetry rotator.
|
||||
// ASCII-only glyph pool — DejaVu Mono renders these at 1ch each, so the
|
||||
// intermediate frames don't shift width.
|
||||
const GLITCH_GLYPHS = '01ABCDEFGHIJKLMNOPQRSTUVWXYZ#@*?!§%';
|
||||
const glyph = () => GLITCH_GLYPHS[(Math.random() * GLITCH_GLYPHS.length) | 0];
|
||||
// Tracks the in-flight scramble per element so a new call can cancel the
|
||||
// previous one (otherwise back-to-back triggers double up timers).
|
||||
const _scrambleHandles = new WeakMap();
|
||||
function scrambleReveal(el, finalText, opts = {}) {
|
||||
const { scrambleMs = 360, stepMs = 50, resolveStepMs = 60 } = opts;
|
||||
const prev = _scrambleHandles.get(el);
|
||||
if (prev) { clearInterval(prev.s); clearInterval(prev.r); }
|
||||
const len = finalText.length;
|
||||
if (!len) {
|
||||
el.textContent = '';
|
||||
el.classList.remove('glitching');
|
||||
_scrambleHandles.delete(el);
|
||||
return;
|
||||
}
|
||||
el.classList.add('glitching');
|
||||
const scrambleSteps = Math.max(1, Math.floor(scrambleMs / stepMs));
|
||||
const handle = { s: null, r: null };
|
||||
_scrambleHandles.set(el, handle);
|
||||
let step = 0;
|
||||
handle.s = setInterval(() => {
|
||||
let s = '';
|
||||
for (let i = 0; i < len; i++) s += glyph();
|
||||
el.textContent = s;
|
||||
if (++step < scrambleSteps) return;
|
||||
clearInterval(handle.s); handle.s = null;
|
||||
let resolved = 0;
|
||||
handle.r = setInterval(() => {
|
||||
resolved++;
|
||||
let s = finalText.slice(0, resolved);
|
||||
for (let i = resolved; i < len; i++) s += glyph();
|
||||
el.textContent = s;
|
||||
if (resolved < len) return;
|
||||
clearInterval(handle.r); handle.r = null;
|
||||
el.textContent = finalText;
|
||||
el.classList.remove('glitching');
|
||||
_scrambleHandles.delete(el);
|
||||
}, resolveStepMs);
|
||||
}, stepMs);
|
||||
}
|
||||
|
||||
// ───────── Rig name in the top HUD ─────────
|
||||
// Reads telemetry.js's window.__TEL.rig (set by telemetry.sh per-rig).
|
||||
// Settles on the real name, then idle-reglitches every ~9s.
|
||||
const rigNameEl = document.getElementById('rigName');
|
||||
const RIG_NAME = (window.__TEL && window.__TEL.rig) || 'UNKNOWN';
|
||||
const upperRig = RIG_NAME.toUpperCase();
|
||||
const scrambleRig = ({ initial = false } = {}) => {
|
||||
if (!upperRig.length) { rigNameEl.textContent = '--'; return; }
|
||||
scrambleReveal(rigNameEl, upperRig, {
|
||||
scrambleMs: initial ? 600 : 360, stepMs: 50, resolveStepMs: 60,
|
||||
});
|
||||
};
|
||||
// First reveal happens shortly after page load; then idle re-glitch.
|
||||
setTimeout(() => scrambleRig({ initial: true }), 600);
|
||||
setInterval(scrambleRig, 9000);
|
||||
|
||||
// ───────── Telemetry: rotating real-data subtitle ─────────
|
||||
// All lines derive from telemetry.js (window.__TEL), generated by telemetry.sh.
|
||||
const rigEl = document.getElementById('rig');
|
||||
const tel = window.__TEL || null;
|
||||
|
||||
// Compact CPU model: drop "(R)/(TM)" and "X-Core Processor" filler
|
||||
const shortCpu = (m) => (m || '')
|
||||
.replace(/\(R\)|\(TM\)/g, '')
|
||||
.replace(/\s+\S+-Core\s+Processor\b/i, '')
|
||||
.replace(/\s+Processor\b/i, '')
|
||||
.replace(/\s+CPU\b.*$/i, '')
|
||||
.replace(/\s+@.*$/, '')
|
||||
.replace(/\s+/g, ' ')
|
||||
.trim();
|
||||
|
||||
const lines = [
|
||||
// CPU + MEM — one combined line
|
||||
() => {
|
||||
if (!tel?.cpu?.model) return null;
|
||||
let s = `CPU · ${shortCpu(tel.cpu.model)}`;
|
||||
if (tel.cpu.threads) s += ` · ${tel.cpu.threads}T`;
|
||||
if (tel.mem?.totalGB) s += ` · MEM ${tel.mem.totalGB} GB`;
|
||||
return s;
|
||||
},
|
||||
|
||||
// GPU
|
||||
() => {
|
||||
if (!tel?.gpu?.name) return null;
|
||||
let s = `GPU · ${tel.gpu.name}`;
|
||||
if (tel.gpu.vramTotalMB) s += ` · ${(tel.gpu.vramTotalMB / 1024).toFixed(0)} GB VRAM`;
|
||||
return s;
|
||||
},
|
||||
|
||||
// OBS output: resolution, fps, encoder
|
||||
() => {
|
||||
const o = tel?.obs;
|
||||
if (!o?.output?.w) return null;
|
||||
let s = `OUTPUT · ${o.output.w}×${o.output.h}`;
|
||||
if (o.fps) s += ` @ ${o.fps} FPS`;
|
||||
if (o.stream?.encoder) s += ` · ${o.stream.encoder}`;
|
||||
return s;
|
||||
},
|
||||
|
||||
// OBS stream: rate control + bitrate + h.264 profile
|
||||
() => {
|
||||
const s = tel?.obs?.stream;
|
||||
if (!s) return null;
|
||||
const parts = [];
|
||||
if (s.rateControl) parts.push(s.rateControl);
|
||||
if (s.bitrateKbps) parts.push(`${s.bitrateKbps} kbps`);
|
||||
if (s.profile) parts.push(s.profile.toUpperCase());
|
||||
return parts.length ? `STREAM · ${parts.join(' · ')}` : null;
|
||||
},
|
||||
|
||||
// Kernel
|
||||
() => tel?.host?.kernel ? `KERNEL · ${tel.host.kernel}` : null,
|
||||
];
|
||||
|
||||
let lineIdx = 0;
|
||||
// Pick the next non-null line, advancing lineIdx past dead slots.
|
||||
const nextLine = () => {
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const v = lines[lineIdx]();
|
||||
if (v) return v;
|
||||
lineIdx = (lineIdx + 1) % lines.length;
|
||||
}
|
||||
return '— TELEMETRY OFFLINE —';
|
||||
};
|
||||
|
||||
// Initial paint goes in directly so the page loads with content visible;
|
||||
// every subsequent transition uses the scramble reveal (same effect as the
|
||||
// top rig identifier).
|
||||
rigEl.textContent = nextLine();
|
||||
// Bottom lines are much longer than the rig name (~22–55 chars vs ~5–8),
|
||||
// so adapt the per-char resolve step to keep total reveal under ~700ms.
|
||||
const swapLine = () => {
|
||||
const text = nextLine();
|
||||
const len = Math.max(text.length, 1);
|
||||
scrambleReveal(rigEl, text, {
|
||||
scrambleMs: 280,
|
||||
stepMs: 45,
|
||||
resolveStepMs: Math.max(15, Math.floor(700 / len)),
|
||||
});
|
||||
};
|
||||
setInterval(() => {
|
||||
lineIdx = (lineIdx + 1) % lines.length;
|
||||
swapLine();
|
||||
}, 6000);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
42
archived/scenes/landing/telemetry.json
Normal file
42
archived/scenes/landing/telemetry.json
Normal file
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"collectedAt": "2026-04-26T20:17:38Z",
|
||||
"rig": "Ignia",
|
||||
"cpu": {
|
||||
"model": "AMD Ryzen 5",
|
||||
"threads": 12
|
||||
},
|
||||
"mem": {
|
||||
"totalGB": 32
|
||||
},
|
||||
"host": {
|
||||
"kernel": "Arch Linux 6.18.23-1-lts"
|
||||
},
|
||||
"gpu": {
|
||||
"name": "NVIDIA GeForce RTX 3060 Ti",
|
||||
"vramTotalMB": 8192
|
||||
},
|
||||
"obs": {
|
||||
"profile": "ophi118",
|
||||
"renderer": "OpenGL",
|
||||
"outputMode": "Advanced",
|
||||
"canvas": { "w": 2560, "h": 1336 },
|
||||
"output": { "w": 1920, "h": 1080 },
|
||||
"fps": 30,
|
||||
"color": {
|
||||
"format": "NV12",
|
||||
"space": "709",
|
||||
"range": "Partial"
|
||||
},
|
||||
"stream": {
|
||||
"encoder": "x264",
|
||||
"rateControl": "CBR",
|
||||
"bitrateKbps": null,
|
||||
"keyintSec": 2,
|
||||
"profile": "high"
|
||||
},
|
||||
"audio": {
|
||||
"sampleRateHz": 48000,
|
||||
"channels": "Stereo"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user