Scrolling text: 'side edges' mode with characters stacked vertically on both borders
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
8db2578eba
commit
35f7addb03
4 files changed
+72
-11
No files matched your search
@@ -257,6 +257,7 @@
|
|||||||
<option value="h">➡️ Orizzontale</option>
|
<option value="h">➡️ Orizzontale</option>
|
||||||
<option value="vup">⬆️ Verticale (su)</option>
|
<option value="vup">⬆️ Verticale (su)</option>
|
||||||
<option value="vdown">⬇️ Verticale (giù)</option>
|
<option value="vdown">⬇️ Verticale (giù)</option>
|
||||||
|
<option value="sides">↕️ Bordi laterali (caratteri impilati)</option>
|
||||||
</select>
|
</select>
|
||||||
<label>Velocità testo <span id="ticker-speed-val">1.0×</span></label>
|
<label>Velocità testo <span id="ticker-speed-val">1.0×</span></label>
|
||||||
<input type="range" id="ticker-speed" min="0.2" max="4" step="0.1" value="1" />
|
<input type="range" id="ticker-speed" min="0.2" max="4" step="0.1" value="1" />
|
||||||
|
|||||||
@@ -29,6 +29,12 @@
|
|||||||
<!-- Scrolling text ticker -->
|
<!-- Scrolling text ticker -->
|
||||||
<div id="ticker"><div id="ticker-track"><span class="tick-copy"></span><span class="tick-copy"></span></div></div>
|
<div id="ticker"><div id="ticker-track"><span class="tick-copy"></span><span class="tick-copy"></span></div></div>
|
||||||
|
|
||||||
|
<!-- Side text: vertical stacked characters scrolling on both edges -->
|
||||||
|
<div id="side-text">
|
||||||
|
<div class="side-col left"><div class="side-track"><span class="side-copy"></span><span class="side-copy"></span></div></div>
|
||||||
|
<div class="side-col right"><div class="side-track"><span class="side-copy"></span><span class="side-copy"></span></div></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div id="drop-hint">
|
<div id="drop-hint">
|
||||||
<div class="big">🎛 In attesa dell'audio…</div>
|
<div class="big">🎛 In attesa dell'audio…</div>
|
||||||
<div class="small">Usa il pannello di controllo sull'altro schermo</div>
|
<div class="small">Usa il pannello di controllo sull'altro schermo</div>
|
||||||
|
|||||||
+35
-11
@@ -127,7 +127,7 @@ function composeFrame() {
|
|||||||
}
|
}
|
||||||
recCtx.globalAlpha = 1;
|
recCtx.globalAlpha = 1;
|
||||||
|
|
||||||
if (ticker.classList.contains('show')) {
|
if (ticker.classList.contains('show') || sideText.classList.contains('show')) {
|
||||||
recCtx.textBaseline = 'middle';
|
recCtx.textBaseline = 'middle';
|
||||||
for (const span of tickerLetters()) {
|
for (const span of tickerLetters()) {
|
||||||
const txt = span.textContent;
|
const txt = span.textContent;
|
||||||
@@ -233,6 +233,9 @@ function setLogo(i, url) {
|
|||||||
const ticker = $('#ticker');
|
const ticker = $('#ticker');
|
||||||
const tickerTrack = $('#ticker-track');
|
const tickerTrack = $('#ticker-track');
|
||||||
const tickCopies = ticker.querySelectorAll('.tick-copy');
|
const tickCopies = ticker.querySelectorAll('.tick-copy');
|
||||||
|
const sideText = $('#side-text');
|
||||||
|
const sideCopies = sideText.querySelectorAll('.side-copy');
|
||||||
|
let tickerVisible = false, tickerDir = 'h';
|
||||||
function buildLetters(txt) {
|
function buildLetters(txt) {
|
||||||
const full = (txt || '') + ' • ';
|
const full = (txt || '') + ' • ';
|
||||||
let html = '';
|
let html = '';
|
||||||
@@ -243,9 +246,24 @@ function buildLetters(txt) {
|
|||||||
}
|
}
|
||||||
return html;
|
return html;
|
||||||
}
|
}
|
||||||
function setTickerText(t) { const h = buildLetters(t); tickCopies.forEach(c => c.innerHTML = h); }
|
function setTickerText(t) {
|
||||||
function setTickerSpeed(m) { tickerTrack.style.setProperty('--ticker-dur', (18 / m) + 's'); }
|
const h = buildLetters(t);
|
||||||
function tickerLetters() { return tickerTrack.querySelectorAll('.tl'); }
|
tickCopies.forEach(c => c.innerHTML = h);
|
||||||
|
sideCopies.forEach(c => c.innerHTML = h);
|
||||||
|
}
|
||||||
|
function setTickerSpeed(m) { document.documentElement.style.setProperty('--ticker-dur', (18 / m) + 's'); }
|
||||||
|
function tickerLetters() {
|
||||||
|
let out = [];
|
||||||
|
if (ticker.classList.contains('show')) out = out.concat([...tickerTrack.querySelectorAll('.tl')]);
|
||||||
|
if (sideText.classList.contains('show')) out = out.concat([...sideText.querySelectorAll('.tl')]);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
function styleBoth(prop, value) { tickerTrack.style[prop] = value; sideText.style[prop] = value; }
|
||||||
|
function updateTickerVis() {
|
||||||
|
const sides = tickerDir === 'sides';
|
||||||
|
ticker.classList.toggle('show', tickerVisible && !sides);
|
||||||
|
sideText.classList.toggle('show', tickerVisible && sides);
|
||||||
|
}
|
||||||
ticker.classList.add('pos-bottom');
|
ticker.classList.add('pos-bottom');
|
||||||
ticker.classList.add('dir-h');
|
ticker.classList.add('dir-h');
|
||||||
setTickerSpeed(1);
|
setTickerSpeed(1);
|
||||||
@@ -384,23 +402,29 @@ djv.onControl(async (m) => {
|
|||||||
case 'logoOpacity': logos[m.index].style.opacity = m.value; break;
|
case 'logoOpacity': logos[m.index].style.opacity = m.value; break;
|
||||||
|
|
||||||
case 'tickerText': setTickerText(m.text); break;
|
case 'tickerText': setTickerText(m.text); break;
|
||||||
case 'tickerOn': ticker.classList.toggle('show', m.on); break;
|
case 'tickerOn': tickerVisible = m.on; updateTickerVis(); break;
|
||||||
case 'tickerPos':
|
case 'tickerPos':
|
||||||
ticker.classList.remove('pos-bottom', 'pos-top', 'pos-middle');
|
ticker.classList.remove('pos-bottom', 'pos-top', 'pos-middle');
|
||||||
ticker.classList.add('pos-' + m.pos);
|
ticker.classList.add('pos-' + m.pos);
|
||||||
break;
|
break;
|
||||||
case 'tickerSpeed': setTickerSpeed(m.mult); break;
|
case 'tickerSpeed': setTickerSpeed(m.mult); break;
|
||||||
case 'tickerDir':
|
case 'tickerDir':
|
||||||
|
tickerDir = m.value;
|
||||||
|
if (m.value !== 'sides') {
|
||||||
ticker.classList.remove('dir-h', 'dir-vup', 'dir-vdown');
|
ticker.classList.remove('dir-h', 'dir-vup', 'dir-vdown');
|
||||||
ticker.classList.add('dir-' + m.value);
|
ticker.classList.add('dir-' + m.value);
|
||||||
|
}
|
||||||
|
updateTickerVis();
|
||||||
break;
|
break;
|
||||||
case 'tickerFont': tickerTrack.style.fontFamily = m.value; break;
|
case 'tickerFont': styleBoth('fontFamily', m.value); break;
|
||||||
case 'tickerSize': tickerTrack.style.fontSize = m.value + 'vh'; break;
|
case 'tickerSize': styleBoth('fontSize', m.value + 'vh'); break;
|
||||||
case 'tickerWeight': tickerTrack.style.fontWeight = m.on ? '800' : '400'; break;
|
case 'tickerWeight': styleBoth('fontWeight', m.on ? '800' : '400'); break;
|
||||||
case 'tickerColor': tickerTrack.style.color = m.value; break;
|
case 'tickerColor': styleBoth('color', m.value); break;
|
||||||
case 'tickerFx':
|
case 'tickerFx':
|
||||||
tickerTrack.classList.remove('fx-updown', 'fx-wave', 'fx-zoom', 'fx-flash', 'fx-rotate');
|
[tickerTrack, sideText].forEach(el => {
|
||||||
if (m.value && m.value !== 'none') tickerTrack.classList.add('fx-' + m.value);
|
el.classList.remove('fx-updown', 'fx-wave', 'fx-zoom', 'fx-flash', 'fx-rotate');
|
||||||
|
if (m.value && m.value !== 'none') el.classList.add('fx-' + m.value);
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -529,6 +529,36 @@ body.output { cursor: none; background: #000; }
|
|||||||
#ticker.dir-vdown #ticker-track { animation: ticker-scroll-vdown var(--ticker-dur, 18s) linear infinite; }
|
#ticker.dir-vdown #ticker-track { animation: ticker-scroll-vdown var(--ticker-dur, 18s) linear infinite; }
|
||||||
@keyframes ticker-scroll-vup { from { transform: translateY(0); } to { transform: translateY(-50%); } }
|
@keyframes ticker-scroll-vup { from { transform: translateY(0); } to { transform: translateY(-50%); } }
|
||||||
@keyframes ticker-scroll-vdown { from { transform: translateY(-50%); } to { transform: translateY(0); } }
|
@keyframes ticker-scroll-vdown { from { transform: translateY(-50%); } to { transform: translateY(0); } }
|
||||||
|
|
||||||
|
/* Side text: vertical stacked characters scrolling on both edges */
|
||||||
|
#side-text {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
z-index: 6;
|
||||||
|
pointer-events: none;
|
||||||
|
display: none;
|
||||||
|
font-size: 6vh;
|
||||||
|
font-weight: 800;
|
||||||
|
color: #fff;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
#side-text.show { display: block; }
|
||||||
|
.side-col { position: absolute; top: 0; bottom: 0; overflow: hidden; display: flex; }
|
||||||
|
.side-col.left { left: 1.5vw; }
|
||||||
|
.side-col.right { right: 1.5vw; }
|
||||||
|
.side-track { display: flex; flex-direction: column; align-items: center; will-change: transform; }
|
||||||
|
.side-col.left .side-track { animation: side-scroll-down var(--ticker-dur, 18s) linear infinite; }
|
||||||
|
.side-col.right .side-track { animation: side-scroll-up var(--ticker-dur, 18s) linear infinite; }
|
||||||
|
.side-copy { display: flex; flex-direction: column; align-items: center; padding: 18vh 0; }
|
||||||
|
.side-copy .tl {
|
||||||
|
display: block;
|
||||||
|
line-height: 1.0;
|
||||||
|
letter-spacing: 0;
|
||||||
|
text-shadow: 0 0 calc(8px + var(--ticker-glow, 0px)) rgba(140,180,255,0.9),
|
||||||
|
0 2px 20px rgba(0,0,0,0.8);
|
||||||
|
}
|
||||||
|
@keyframes side-scroll-up { from { transform: translateY(0); } to { transform: translateY(-50%); } }
|
||||||
|
@keyframes side-scroll-down { from { transform: translateY(-50%); } to { transform: translateY(0); } }
|
||||||
.tl {
|
.tl {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
white-space: pre;
|
white-space: pre;
|
||||||
|
|||||||
Reference in new issue
Block a user