Replace CSS robot with animated character switcher
Swaps DANCEBOT-9000 CSS robot for a pool of APNG characters that cycle randomly every 8s and on track change: 4 skeleton GIFs, a dancing baby (YouTube clip), and Pepe. Background removal done with ffmpeg colorkey. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
5378772d8a
commit
9fbfb0592d
7 changed files with 30 additions and 79 deletions
|
|
@ -208,11 +208,15 @@ html, body {
|
||||||
.robot-wrap {
|
.robot-wrap {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
bottom: 40%;
|
bottom: 32%;
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
filter:
|
}
|
||||||
drop-shadow(0 0 35px rgba(0,200,255,0.25))
|
|
||||||
drop-shadow(0 20px 15px rgba(0,0,80,0.6));
|
.skeleton-gif {
|
||||||
|
display: block;
|
||||||
|
height: 40vh;
|
||||||
|
width: auto;
|
||||||
|
filter: drop-shadow(0 0 20px rgba(0,200,255,0.4));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Entire robot bounces on the beat (0.5s = 1 beat at 120 BPM) */
|
/* Entire robot bounces on the beat (0.5s = 1 beat at 120 BPM) */
|
||||||
|
|
@ -694,81 +698,7 @@ html, body {
|
||||||
|
|
||||||
<!-- ===================== ROBOT ===================== -->
|
<!-- ===================== ROBOT ===================== -->
|
||||||
<div class="robot-wrap">
|
<div class="robot-wrap">
|
||||||
<div class="robot">
|
<img src="skeleton6.apng" class="skeleton-gif" alt="skeleton">
|
||||||
|
|
||||||
<!-- Antenna -->
|
|
||||||
<div class="antenna-wrap">
|
|
||||||
<div class="antenna-stick">
|
|
||||||
<div class="antenna-ball"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Head -->
|
|
||||||
<div class="head">
|
|
||||||
<div class="eyes">
|
|
||||||
<div class="eye"></div>
|
|
||||||
<div class="eye"></div>
|
|
||||||
</div>
|
|
||||||
<div class="mouth-panel">
|
|
||||||
<div class="mouth-seg"></div>
|
|
||||||
<div class="mouth-seg"></div>
|
|
||||||
<div class="mouth-seg"></div>
|
|
||||||
<div class="mouth-seg"></div>
|
|
||||||
<div class="mouth-seg"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Neck -->
|
|
||||||
<div class="neck"></div>
|
|
||||||
|
|
||||||
<!-- Middle row: left arm, torso, right arm -->
|
|
||||||
<div class="middle">
|
|
||||||
<div class="shoulder"></div>
|
|
||||||
<div class="arm left">
|
|
||||||
<div class="hand"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div style="display:flex;flex-direction:column;align-items:center;">
|
|
||||||
<div class="torso">
|
|
||||||
<div class="chest-screen" id="chestScreen">
|
|
||||||
<div class="eq-row" id="eqTop"></div>
|
|
||||||
<div class="chest-logo">♪ ♫ ♪</div>
|
|
||||||
<div class="eq-row" id="eqBot"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="hip">
|
|
||||||
<div class="rivet"></div>
|
|
||||||
<div class="rivet"></div>
|
|
||||||
<div class="rivet"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="arm right">
|
|
||||||
<div class="hand"></div>
|
|
||||||
</div>
|
|
||||||
<div class="shoulder"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Legs -->
|
|
||||||
<div class="legs">
|
|
||||||
<div class="leg-grp">
|
|
||||||
<div class="upper-leg left"></div>
|
|
||||||
<div class="knee"></div>
|
|
||||||
<div class="lower-leg left">
|
|
||||||
<div class="foot"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="leg-grp">
|
|
||||||
<div class="upper-leg right"></div>
|
|
||||||
<div class="knee"></div>
|
|
||||||
<div class="lower-leg right">
|
|
||||||
<div class="foot"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div><!-- .robot -->
|
|
||||||
|
|
||||||
<div class="robot-shadow"></div>
|
<div class="robot-shadow"></div>
|
||||||
</div><!-- .robot-wrap -->
|
</div><!-- .robot-wrap -->
|
||||||
|
|
||||||
|
|
@ -1038,6 +968,7 @@ function updateMusic(artist, title) {
|
||||||
: (title || artist || '— —');
|
: (title || artist || '— —');
|
||||||
if (el.textContent === text) return;
|
if (el.textContent === text) return;
|
||||||
el.textContent = text;
|
el.textContent = text;
|
||||||
|
pickSkeleton();
|
||||||
// scroll only if text is long
|
// scroll only if text is long
|
||||||
const wrap = el.parentElement;
|
const wrap = el.parentElement;
|
||||||
el.classList.toggle('short', el.scrollWidth <= wrap.clientWidth + 10);
|
el.classList.toggle('short', el.scrollWidth <= wrap.clientWidth + 10);
|
||||||
|
|
@ -1061,6 +992,26 @@ function nextDanceStyle() {
|
||||||
document.body.setAttribute('data-dance', 'bounce');
|
document.body.setAttribute('data-dance', 'bounce');
|
||||||
setInterval(nextDanceStyle, 8000);
|
setInterval(nextDanceStyle, 8000);
|
||||||
|
|
||||||
|
/* ============================================================
|
||||||
|
SKELETON SWITCHER
|
||||||
|
Add new files to SKELETONS to include them in the rotation.
|
||||||
|
Switches on music change and randomly every 16 beats (8s).
|
||||||
|
============================================================ */
|
||||||
|
const SKELETONS = ['skeleton.apng', 'skeleton2.apng', 'skeleton3.apng', 'skeleton4.apng', 'skeleton5.apng', 'skeleton6.apng'];
|
||||||
|
const skeletonImg = document.querySelector('.skeleton-gif');
|
||||||
|
let currentSkel = 5;
|
||||||
|
|
||||||
|
function pickSkeleton() {
|
||||||
|
if (SKELETONS.length < 2) return;
|
||||||
|
let next;
|
||||||
|
do { next = Math.floor(Math.random() * SKELETONS.length); }
|
||||||
|
while (next === currentSkel);
|
||||||
|
currentSkel = next;
|
||||||
|
skeletonImg.src = SKELETONS[currentSkel];
|
||||||
|
}
|
||||||
|
|
||||||
|
setInterval(pickSkeleton, 8000);
|
||||||
|
|
||||||
/* ============================================================
|
/* ============================================================
|
||||||
DEV SHIM — only active when served via HTTP (not from QML)
|
DEV SHIM — only active when served via HTTP (not from QML)
|
||||||
Simulates playerctl updates so the music ticker works in-browser.
|
Simulates playerctl updates so the music ticker works in-browser.
|
||||||
|
|
|
||||||
BIN
plugin/contents/ui/skeleton.apng
Normal file
BIN
plugin/contents/ui/skeleton.apng
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.1 MiB |
BIN
plugin/contents/ui/skeleton2.apng
Normal file
BIN
plugin/contents/ui/skeleton2.apng
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.9 MiB |
BIN
plugin/contents/ui/skeleton3.apng
Normal file
BIN
plugin/contents/ui/skeleton3.apng
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 MiB |
BIN
plugin/contents/ui/skeleton4.apng
Normal file
BIN
plugin/contents/ui/skeleton4.apng
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 35 MiB |
BIN
plugin/contents/ui/skeleton5.apng
Normal file
BIN
plugin/contents/ui/skeleton5.apng
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 13 MiB |
BIN
plugin/contents/ui/skeleton6.apng
Normal file
BIN
plugin/contents/ui/skeleton6.apng
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2 MiB |
Loading…
Add table
Add a link
Reference in a new issue