···237237238238 animation: 30s linear forwards infinite spin;
239239240240+ @media (prefers-reduced-motion: reduce) {
241241+ animation-delay: -20s;
242242+ animation-play-state: paused;
243243+ }
244244+240245 [data-playing="false"] & {
241246 animation-play-state: paused;
242247 }
···265270 height: calc((60 / 3) * 1cqw);
266271267272 animation: 60s linear 2.5s infinite forwards head-move;
273273+274274+ @media (prefers-reduced-motion: reduce) {
275275+ animation-delay: -20s;
276276+ animation-play-state: paused;
277277+ }
268278269279 [data-playing="false"] & {
270280 animation-play-state: paused;
···564574 * ANIMATIONS *
565575 **************/
566576567567- // delete css animations since we r going to use our own
568568- elements.spinner.forEach((el) =>
569569- el.getAnimations().forEach((anim) => anim.cancel()),
570570- );
577577+ const reducedMotion = window.matchMedia("(prefers-reduced-motion:reduce)");
571578572579 const playHeadAnimation = [
573580 {
···594601 // start state is infered
595602 const goToStartAnimation = [{ rotate: "0deg" }];
596603597597- const animations = elements.spinner.map((el) =>
598598- el.animate(playHeadAnimation, {
599599- duration: 30 * 1000,
600600- fill: "forwards",
601601- iterations: Infinity,
602602- }),
603603- );
604604+ let animations: Animation[] = [];
605605+606606+ // we only do js animations if reduced motion is disabled
607607+ // if reduce motion is reduced, the static css animations are fine
608608+ if (!reducedMotion.matches) {
609609+ // delete css animations since we r going to use our own
610610+ elements.spinner.forEach((el) =>
611611+ el.getAnimations().forEach((anim) => anim.cancel()),
612612+ );
613613+614614+ animations = elements.spinner.map((el) =>
615615+ el.animate(playHeadAnimation, {
616616+ duration: 30 * 1000,
617617+ fill: "forwards",
618618+ iterations: Infinity,
619619+ }),
620620+ );
604621605605- if (elements.player.dataset.playing === "false") {
606606- // dont play animations
607607- animations.forEach((anim) => anim.pause());
622622+ // pause the animations if nothing is playing or reduced motion is enabled
623623+ if (elements.player.dataset.playing === "false") {
624624+ // dont play animations
625625+ animations.forEach((anim) => anim.pause());
626626+ }
608627 }
609628610629 /************
···648667 // there is now a difference between the previous setting and the new setting
649668 // so it is worth updating the UI
650669651651- // spinner head animation:
652652- // 1. pause current animation.
653653- animations.forEach((anim) => anim.pause());
654654- elements.spinner.forEach((el) =>
655655- // 2. send the playback head to the start
656656- el
657657- .animate(goToStartAnimation, {
658658- duration: 2.5 * 1000,
659659- easing: "ease-in-out",
660660- })
661661- // 3. when the playback head is at the start
662662- .finished.then(async () => {
663663- // 4. update the record art
664664- elements.recordArt.src = data ? data?.art : "https://undefined";
670670+ if (!reducedMotion) {
671671+ // spinner head animation:
672672+ // 1. pause current animation.
673673+ animations.forEach((anim) => anim.pause());
674674+ elements.spinner.forEach((el) =>
675675+ // 2. send the playback head to the start
676676+ el
677677+ .animate(goToStartAnimation, {
678678+ duration: 2.5 * 1000,
679679+ easing: "ease-in-out",
680680+ })
681681+ // 3. when the playback head is at the start
682682+ .finished.then(async () => {
683683+ // 4. update the record art
684684+ elements.recordArt.src = data ? data?.art : "https://undefined";
685685+686686+ // 5. update popup
687687+ if (data) elements.nowPlaying.updateMetadata(data);
688688+ else elements.nowPlaying.nothingPlaying();
665689666666- // 5. update popup
667667- if (data) elements.nowPlaying.updateMetadata(data);
668668- else elements.nowPlaying.nothingPlaying();
690690+ // 6. reset the position of the infinite animation
691691+ animations.forEach((anim) => (anim.currentTime = 0));
669692670670- // 6. reset the position of the infinite animation
671671- animations.forEach((anim) => (anim.currentTime = 0));
693693+ // 7. if new track is not null then, after 2s
694694+ if (data)
695695+ setTimeout(() => {
696696+ // 8. resume the infinite animation
697697+ animations.forEach((anim) => anim.play());
698698+ }, 2000);
672699673673- // 7. if new track is not null then, after 2s
674674- if (data)
675675- setTimeout(() => {
676676- // 8. resume the infinite animation
677677- animations.forEach((anim) => anim.play());
678678- }, 2000);
700700+ // 9. make sure the record is in the right state (playing or paused)
701701+ elements.player.dataset.playing = data ? "true" : "false";
702702+ }),
703703+ );
704704+ // the user requested reduced motion, so instantly update state
705705+ } else {
706706+ elements.recordArt.src = data ? data?.art : "https://undefined";
707707+708708+ if (data) elements.nowPlaying.updateMetadata(data);
709709+ else elements.nowPlaying.nothingPlaying();
679710680680- // 9. make sure the record is in the right state (playing or paused)
681681- elements.player.dataset.playing = data ? "true" : "false";
682682- }),
683683- );
711711+ elements.player.dataset.playing = data ? "true" : "false";
712712+ }
684713 }
685714 } finally {
686715 prev = data;