Add chain triggers, fix overlay→light type, fix signal source segments
This commit is contained in:
@@ -19,8 +19,6 @@
|
|||||||
--light-bg: rgba(42, 10, 42, 0.55);
|
--light-bg: rgba(42, 10, 42, 0.55);
|
||||||
--video-color: #4d4;
|
--video-color: #4d4;
|
||||||
--video-bg: rgba(10, 42, 10, 0.55);
|
--video-bg: rgba(10, 42, 10, 0.55);
|
||||||
--overlay-color: #2cb;
|
|
||||||
--overlay-bg: rgba(10, 34, 34, 0.55);
|
|
||||||
--audio-color: #58f;
|
--audio-color: #58f;
|
||||||
--audio-bg: rgba(10, 10, 42, 0.55);
|
--audio-bg: rgba(10, 10, 42, 0.55);
|
||||||
--delay-color: #999;
|
--delay-color: #999;
|
||||||
@@ -109,7 +107,6 @@ header h1 { font-size: 16px; font-weight: 600; letter-spacing: 0.05em; }
|
|||||||
}
|
}
|
||||||
.block.light { color: var(--light-color); border-color: var(--light-color); background: var(--light-bg); }
|
.block.light { color: var(--light-color); border-color: var(--light-color); background: var(--light-bg); }
|
||||||
.block.video { color: var(--video-color); border-color: var(--video-color); background: var(--video-bg); }
|
.block.video { color: var(--video-color); border-color: var(--video-color); background: var(--video-bg); }
|
||||||
.block.overlay { color: var(--overlay-color); border-color: var(--overlay-color); background: var(--overlay-bg); }
|
|
||||||
.block.audio { color: var(--audio-color); border-color: var(--audio-color); background: var(--audio-bg); }
|
.block.audio { color: var(--audio-color); border-color: var(--audio-color); background: var(--audio-bg); }
|
||||||
.block.delay { color: var(--delay-color); border-color: var(--delay-color); background: var(--delay-bg); }
|
.block.delay { color: var(--delay-color); border-color: var(--delay-color); background: var(--delay-bg); }
|
||||||
|
|
||||||
@@ -169,27 +166,23 @@ function render(data) {
|
|||||||
const CUE_TRACK = '_cue';
|
const CUE_TRACK = '_cue';
|
||||||
const trackIds = [CUE_TRACK, ...data.tracks.map(t => t.id)];
|
const trackIds = [CUE_TRACK, ...data.tracks.map(t => t.id)];
|
||||||
|
|
||||||
function ref(block, signal) { return block + ':' + signal; }
|
function ref(b, s) { return b + ':' + s; }
|
||||||
|
|
||||||
const triggerTargetSet = new Set();
|
|
||||||
const triggerSourceSet = new Set();
|
const triggerSourceSet = new Set();
|
||||||
data.triggers.forEach(t => {
|
data.triggers.forEach(t => triggerSourceSet.add(ref(t.source.block, t.source.signal)));
|
||||||
triggerSourceSet.add(ref(t.source.block, t.source.signal));
|
|
||||||
t.targets.forEach(tgt => triggerTargetSet.add(ref(tgt.block, tgt.hook)));
|
|
||||||
});
|
|
||||||
|
|
||||||
const trackBlocks = new Map();
|
|
||||||
trackIds.forEach(id => trackBlocks.set(id, []));
|
|
||||||
data.blocks.forEach(b => {
|
|
||||||
const tid = b.type === 'cue' ? CUE_TRACK : b.track;
|
|
||||||
trackBlocks.get(tid).push(b.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
function blockTrack(bid) {
|
function blockTrack(bid) {
|
||||||
const b = blockMap.get(bid);
|
const b = blockMap.get(bid);
|
||||||
return b.type === 'cue' ? CUE_TRACK : b.track;
|
return b.type === 'cue' ? CUE_TRACK : b.track;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isChain(trigger) {
|
||||||
|
const src = trigger.source;
|
||||||
|
if (src.signal !== 'END' || trigger.targets.length !== 1) return false;
|
||||||
|
return trigger.targets[0].hook === 'START' &&
|
||||||
|
blockTrack(src.block) === blockTrack(trigger.targets[0].block);
|
||||||
|
}
|
||||||
|
|
||||||
document.getElementById('header-status').innerHTML =
|
document.getElementById('header-status').innerHTML =
|
||||||
'<span><span class="status-dot"></span>QLab Connected</span>' +
|
'<span><span class="status-dot"></span>QLab Connected</span>' +
|
||||||
'<span>Show: ' + data.show + '</span>' +
|
'<span>Show: ' + data.show + '</span>' +
|
||||||
@@ -198,15 +191,9 @@ function render(data) {
|
|||||||
const active = new Map();
|
const active = new Map();
|
||||||
const pendingEnds = new Set();
|
const pendingEnds = new Set();
|
||||||
const pendingTitles = new Set();
|
const pendingTitles = new Set();
|
||||||
|
const titled = new Set();
|
||||||
const rows = [];
|
const rows = [];
|
||||||
|
|
||||||
function nextInTrack(bid) {
|
|
||||||
const tid = blockTrack(bid);
|
|
||||||
const seq = trackBlocks.get(tid);
|
|
||||||
const idx = seq.indexOf(bid);
|
|
||||||
return idx < seq.length - 1 ? seq[idx + 1] : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function mid(tid) {
|
function mid(tid) {
|
||||||
const a = active.get(tid);
|
const a = active.get(tid);
|
||||||
return a ? { blockId: a, segment: 'mid' } : { empty: true };
|
return a ? { blockId: a, segment: 'mid' } : { empty: true };
|
||||||
@@ -216,8 +203,8 @@ function render(data) {
|
|||||||
rows.push({ cells, rowClass: rowClass || '' });
|
rows.push({ cells, rowClass: rowClass || '' });
|
||||||
}
|
}
|
||||||
|
|
||||||
function canAutoStart(bid) {
|
function wantTitle(bid) {
|
||||||
return !triggerTargetSet.has(ref(bid, 'START')) && !triggerSourceSet.has(ref(bid, 'START'));
|
if (!titled.has(bid)) pendingTitles.add(bid);
|
||||||
}
|
}
|
||||||
|
|
||||||
function emitTitles() {
|
function emitTitles() {
|
||||||
@@ -227,40 +214,15 @@ function render(data) {
|
|||||||
return t ? { blockId: t, segment: 'mid', title: blockMap.get(t).name } : mid(tid);
|
return t ? { blockId: t, segment: 'mid', title: blockMap.get(t).name } : mid(tid);
|
||||||
});
|
});
|
||||||
addRow(cells);
|
addRow(cells);
|
||||||
|
pendingTitles.forEach(bid => titled.add(bid));
|
||||||
pendingTitles.clear();
|
pendingTitles.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
function doAutoStarts(ended) {
|
function flush() {
|
||||||
const starts = [];
|
|
||||||
ended.forEach(bid => {
|
|
||||||
const next = nextInTrack(bid);
|
|
||||||
if (next && canAutoStart(next)) starts.push(next);
|
|
||||||
});
|
|
||||||
if (starts.length === 0) return;
|
|
||||||
const cells = trackIds.map(tid => {
|
|
||||||
const s = starts.find(bid => blockTrack(bid) === tid);
|
|
||||||
if (s) {
|
|
||||||
active.set(tid, s);
|
|
||||||
pendingTitles.add(s);
|
|
||||||
return { blockId: s, segment: 'start', event: 'START' };
|
|
||||||
}
|
|
||||||
return mid(tid);
|
|
||||||
});
|
|
||||||
addRow(cells);
|
|
||||||
}
|
|
||||||
|
|
||||||
function flush(upcomingSrc) {
|
|
||||||
emitTitles();
|
emitTitles();
|
||||||
if (pendingEnds.size === 0) return;
|
if (pendingEnds.size === 0) return;
|
||||||
|
|
||||||
const holdBack = new Set();
|
const toEnd = [...pendingEnds].filter(bid => !triggerSourceSet.has(ref(bid, 'END')));
|
||||||
if (upcomingSrc) {
|
|
||||||
for (const bid of pendingEnds) {
|
|
||||||
if (upcomingSrc.block === bid && upcomingSrc.signal === 'END') holdBack.add(bid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const toEnd = [...pendingEnds].filter(bid => !holdBack.has(bid));
|
|
||||||
if (toEnd.length === 0) return;
|
if (toEnd.length === 0) return;
|
||||||
|
|
||||||
const cells = trackIds.map(tid => {
|
const cells = trackIds.map(tid => {
|
||||||
@@ -269,31 +231,36 @@ function render(data) {
|
|||||||
});
|
});
|
||||||
addRow(cells);
|
addRow(cells);
|
||||||
toEnd.forEach(bid => { active.delete(blockTrack(bid)); pendingEnds.delete(bid); });
|
toEnd.forEach(bid => { active.delete(blockTrack(bid)); pendingEnds.delete(bid); });
|
||||||
|
|
||||||
doAutoStarts(toEnd);
|
|
||||||
emitTitles();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function processTrigger(trigger) {
|
function processTrigger(trigger) {
|
||||||
const src = trigger.source;
|
const src = trigger.source;
|
||||||
const isCue = src.signal === 'GO';
|
const isCue = src.signal === 'GO';
|
||||||
|
|
||||||
flush(src);
|
flush();
|
||||||
|
|
||||||
if (!isCue) {
|
if (isChain(trigger)) {
|
||||||
const tid = blockTrack(src.block);
|
const tid = blockTrack(src.block);
|
||||||
if (src.signal === 'START') {
|
const tgt = trigger.targets[0].block;
|
||||||
const cur = active.get(tid);
|
if (active.get(tid) === src.block || pendingEnds.has(src.block)) {
|
||||||
if (cur && cur !== src.block) {
|
pendingEnds.delete(src.block);
|
||||||
pendingEnds.delete(cur);
|
const endCells = trackIds.map(t =>
|
||||||
const cells = trackIds.map(t =>
|
t === tid ? { blockId: src.block, segment: 'end', event: 'END' } : mid(t)
|
||||||
t === tid ? { blockId: cur, segment: 'end', event: 'END' } : mid(t)
|
);
|
||||||
);
|
addRow(endCells);
|
||||||
addRow(cells);
|
active.delete(tid);
|
||||||
active.delete(tid);
|
|
||||||
}
|
|
||||||
active.set(tid, src.block);
|
|
||||||
}
|
}
|
||||||
|
active.set(tid, tgt);
|
||||||
|
wantTitle(tgt);
|
||||||
|
const startCells = trackIds.map(t =>
|
||||||
|
t === tid ? { blockId: tgt, segment: 'start', event: 'START' } : mid(t)
|
||||||
|
);
|
||||||
|
addRow(startCells);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isCue && src.signal === 'START' && active.get(blockTrack(src.block)) !== src.block) {
|
||||||
|
active.set(blockTrack(src.block), src.block);
|
||||||
}
|
}
|
||||||
|
|
||||||
emitTitles();
|
emitTitles();
|
||||||
@@ -310,7 +277,8 @@ function render(data) {
|
|||||||
return { cueLabel: blockMap.get(src.block).name };
|
return { cueLabel: blockMap.get(src.block).name };
|
||||||
|
|
||||||
if (!isCue && blockTrack(src.block) === tid) {
|
if (!isCue && blockTrack(src.block) === tid) {
|
||||||
const seg = src.signal === 'START' ? 'start' : src.signal === 'END' ? 'end' : 'mid';
|
const alreadyActive = active.get(tid) === src.block;
|
||||||
|
const seg = alreadyActive ? 'mid' : src.signal === 'START' ? 'start' : src.signal === 'END' ? 'end' : 'mid';
|
||||||
return { blockId: src.block, segment: seg, event: src.signal, isSignal: true };
|
return { blockId: src.block, segment: seg, event: src.signal, isSignal: true };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -320,7 +288,7 @@ function render(data) {
|
|||||||
const isHook = !isCue;
|
const isHook = !isCue;
|
||||||
if (hook === 'START') {
|
if (hook === 'START') {
|
||||||
active.set(tid, bid);
|
active.set(tid, bid);
|
||||||
pendingTitles.add(bid);
|
wantTitle(bid);
|
||||||
return { blockId: bid, segment: 'start', event: 'START', isHook };
|
return { blockId: bid, segment: 'start', event: 'START', isHook };
|
||||||
}
|
}
|
||||||
if (hook === 'END') {
|
if (hook === 'END') {
|
||||||
@@ -339,21 +307,19 @@ function render(data) {
|
|||||||
addRow(cells, rowClass);
|
addRow(cells, rowClass);
|
||||||
|
|
||||||
directEnds.forEach(bid => active.delete(blockTrack(bid)));
|
directEnds.forEach(bid => active.delete(blockTrack(bid)));
|
||||||
doAutoStarts(directEnds);
|
|
||||||
|
|
||||||
if (!isCue) {
|
if (!isCue) {
|
||||||
if (src.signal === 'START') pendingTitles.add(src.block);
|
if (src.signal === 'START' && !pendingTitles.has(src.block)) wantTitle(src.block);
|
||||||
if (src.signal === 'FADE_OUT') pendingEnds.add(src.block);
|
if (src.signal === 'FADE_OUT') pendingEnds.add(src.block);
|
||||||
if (src.signal === 'END') {
|
if (src.signal === 'END') {
|
||||||
active.delete(blockTrack(src.block));
|
active.delete(blockTrack(src.block));
|
||||||
pendingEnds.delete(src.block);
|
pendingEnds.delete(src.block);
|
||||||
doAutoStarts([src.block]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data.triggers.forEach(t => processTrigger(t));
|
data.triggers.forEach(t => processTrigger(t));
|
||||||
flush(null);
|
flush();
|
||||||
emitTitles();
|
emitTitles();
|
||||||
|
|
||||||
const stillActive = [];
|
const stillActive = [];
|
||||||
|
|||||||
@@ -20,10 +20,10 @@
|
|||||||
{"id": "block_01kht41b8deg8ae996tzqay0rg", "type": "light", "track": "track_01kht419m1e65bfgqzj28se459", "name": "SC1 Focus"},
|
{"id": "block_01kht41b8deg8ae996tzqay0rg", "type": "light", "track": "track_01kht419m1e65bfgqzj28se459", "name": "SC1 Focus"},
|
||||||
{"id": "block_01kht41b9neqf84ap7dm3mey9r", "type": "light", "track": "track_01kht419n7esr929mxvsacsy0k", "name": "SC1 Blue 80%"},
|
{"id": "block_01kht41b9neqf84ap7dm3mey9r", "type": "light", "track": "track_01kht419n7esr929mxvsacsy0k", "name": "SC1 Blue 80%"},
|
||||||
{"id": "block_01kht41bawfbhr38a49tjvyahy", "type": "video", "track": "track_01kht419pbfx2992sjpagc0syy", "name": "Sc1 Projection"},
|
{"id": "block_01kht41bawfbhr38a49tjvyahy", "type": "video", "track": "track_01kht419pbfx2992sjpagc0syy", "name": "Sc1 Projection"},
|
||||||
{"id": "block_01kht41bc3evybtn5hqnk6p2f7", "type": "overlay", "track": "track_01kht419qdeb1bjm9qe5acas2f", "name": "Lightning Flash"},
|
{"id": "block_01kht41bc3evybtn5hqnk6p2f7", "type": "video", "track": "track_01kht419qdeb1bjm9qe5acas2f", "name": "Lightning Flash"},
|
||||||
{"id": "block_01kht41bdafggbbm8959svkm4n", "type": "audio", "track": "track_01kht419rffhnayzmgqnnkddtz", "name": "Storm Ambience", "loop": true},
|
{"id": "block_01kht41bdafggbbm8959svkm4n", "type": "audio", "track": "track_01kht419rffhnayzmgqnnkddtz", "name": "Storm Ambience", "loop": true},
|
||||||
{"id": "block_01kht41bejev2997rfps2kpbat", "type": "cue", "name": "Q13 Sc1 Dialog"},
|
{"id": "block_01kht41bejev2997rfps2kpbat", "type": "cue", "name": "Q13 Sc1 Dialog"},
|
||||||
{"id": "block_01kht41bfsfhkvtvze4rh7k7z6", "type": "overlay", "track": "track_01kht419qdeb1bjm9qe5acas2f", "name": "Wave Overlay"},
|
{"id": "block_01kht41bfsfhkvtvze4rh7k7z6", "type": "video", "track": "track_01kht419qdeb1bjm9qe5acas2f", "name": "Wave Overlay"},
|
||||||
{"id": "block_01kht41bgzfjcrkwrvrrjkqs0f", "type": "light", "track": "track_01kht419m1e65bfgqzj28se459", "name": "Dialog Spots"},
|
{"id": "block_01kht41bgzfjcrkwrvrrjkqs0f", "type": "light", "track": "track_01kht419m1e65bfgqzj28se459", "name": "Dialog Spots"},
|
||||||
{"id": "block_01kht41bj7ea89xn71nn5h400a", "type": "light", "track": "track_01kht419n7esr929mxvsacsy0k", "name": "Warm 90%"},
|
{"id": "block_01kht41bj7ea89xn71nn5h400a", "type": "light", "track": "track_01kht419n7esr929mxvsacsy0k", "name": "Warm 90%"},
|
||||||
{"id": "block_01kht41bkee1n81gnfq6bydmm2", "type": "audio", "track": "track_01kht419rffhnayzmgqnnkddtz", "name": "Dialog Underscore"},
|
{"id": "block_01kht41bkee1n81gnfq6bydmm2", "type": "audio", "track": "track_01kht419rffhnayzmgqnnkddtz", "name": "Dialog Underscore"},
|
||||||
@@ -49,6 +49,12 @@
|
|||||||
{"block": "block_01kht41azrenbaxyc2vebv7s4q", "hook": "FADE_OUT"}
|
{"block": "block_01kht41azrenbaxyc2vebv7s4q", "hook": "FADE_OUT"}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"source": {"block": "block_01kht41azrenbaxyc2vebv7s4q", "signal": "END"},
|
||||||
|
"targets": [
|
||||||
|
{"block": "block_01kht41b5zf4ya2044tczm8tz6", "hook": "START"}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"source": {"block": "block_01kht41b4rfnhvk83p9afhp08y", "signal": "GO"},
|
"source": {"block": "block_01kht41b4rfnhvk83p9afhp08y", "signal": "GO"},
|
||||||
"targets": [
|
"targets": [
|
||||||
@@ -57,6 +63,18 @@
|
|||||||
{"block": "block_01kht41b29eyes3b6neh4h56mn", "hook": "FADE_OUT"}
|
{"block": "block_01kht41b29eyes3b6neh4h56mn", "hook": "FADE_OUT"}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"source": {"block": "block_01kht41b10emgt1gfvg7dy60ws", "signal": "END"},
|
||||||
|
"targets": [
|
||||||
|
{"block": "block_01kht41b76ebtraravpknavdm5", "hook": "START"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": {"block": "block_01kht41b76ebtraravpknavdm5", "signal": "END"},
|
||||||
|
"targets": [
|
||||||
|
{"block": "block_01kht41bawfbhr38a49tjvyahy", "hook": "START"}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"source": {"block": "block_01kht41bawfbhr38a49tjvyahy", "signal": "START"},
|
"source": {"block": "block_01kht41bawfbhr38a49tjvyahy", "signal": "START"},
|
||||||
"targets": [
|
"targets": [
|
||||||
@@ -65,6 +83,12 @@
|
|||||||
{"block": "block_01kht41bdafggbbm8959svkm4n", "hook": "START"}
|
{"block": "block_01kht41bdafggbbm8959svkm4n", "hook": "START"}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"source": {"block": "block_01kht41b5zf4ya2044tczm8tz6", "signal": "END"},
|
||||||
|
"targets": [
|
||||||
|
{"block": "block_01kht41b9neqf84ap7dm3mey9r", "hook": "START"}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"source": {"block": "block_01kht41b9neqf84ap7dm3mey9r", "signal": "START"},
|
"source": {"block": "block_01kht41b9neqf84ap7dm3mey9r", "signal": "START"},
|
||||||
"targets": [
|
"targets": [
|
||||||
@@ -86,6 +110,18 @@
|
|||||||
{"block": "block_01kht41bfsfhkvtvze4rh7k7z6", "hook": "START"}
|
{"block": "block_01kht41bfsfhkvtvze4rh7k7z6", "hook": "START"}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"source": {"block": "block_01kht41b9neqf84ap7dm3mey9r", "signal": "END"},
|
||||||
|
"targets": [
|
||||||
|
{"block": "block_01kht41bj7ea89xn71nn5h400a", "hook": "START"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": {"block": "block_01kht41bdafggbbm8959svkm4n", "signal": "END"},
|
||||||
|
"targets": [
|
||||||
|
{"block": "block_01kht41bkee1n81gnfq6bydmm2", "hook": "START"}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"source": {"block": "block_01kht41bkee1n81gnfq6bydmm2", "signal": "START"},
|
"source": {"block": "block_01kht41bkee1n81gnfq6bydmm2", "signal": "START"},
|
||||||
"targets": [
|
"targets": [
|
||||||
@@ -102,6 +138,18 @@
|
|||||||
{"block": "block_01kht41bkee1n81gnfq6bydmm2", "hook": "END"}
|
{"block": "block_01kht41bkee1n81gnfq6bydmm2", "hook": "END"}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"source": {"block": "block_01kht41bgzfjcrkwrvrrjkqs0f", "signal": "END"},
|
||||||
|
"targets": [
|
||||||
|
{"block": "block_01kht41bnxfme95cspptf87j9b", "hook": "START"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": {"block": "block_01kht41bj7ea89xn71nn5h400a", "signal": "END"},
|
||||||
|
"targets": [
|
||||||
|
{"block": "block_01kht41bq2ekwswsf51b0h1bd2", "hook": "START"}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"source": {"block": "block_01kht41bfsfhkvtvze4rh7k7z6", "signal": "END"},
|
"source": {"block": "block_01kht41bfsfhkvtvze4rh7k7z6", "signal": "END"},
|
||||||
"targets": [
|
"targets": [
|
||||||
|
|||||||
Reference in New Issue
Block a user