Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URLs added here will be added as <link>s in order, and before the CSS in the editor. You can use the CSS from another Pen by using its URL and the proper URL extension.

+ add another resource

JavaScript

Babel includes JSX processing.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

Auto Save

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                <svg class="inactivity-ring" viewBox="0 0 50 50" fill="none" xmlns="http://www.w3.org/2000/svg">
  <circle cx="25" cy="25" r="20" stroke-width="10" stroke-linejoin="round" />
</svg>
<main>
  <header>
    <h1>screensaver.js</h1>
  </header>
  <article>
    <p>
      <strong>
        In this demo, leave the page inactive for 4 seconds, and a screensaver will appear using a pop-up. On <code>show</code> it generates the animation behavior and leverages "light dismiss".
      </strong>
    </p>
    <p>Lorem ipsum, dolor, sit amet consectetur adipisicing elit. Repellat illo eum hic possimus, libero voluptates, facere nihil deserunt similique error sunt vero minima enim cupiditate quis velit rem ab repellendus.</p>
    <p>Neque hic veniam cum voluptates quae magnam quisquam saepe. Dolorum quasi amet officiis vero aliquid pariatur commodi repellendus. Quos iure nobis doloremque ipsum facere nostrum neque adipisci hic labore voluptates?</p>
    <p>Mollitia beatae, repellat est laboriosam officiis? Earum veritatis incidunt explicabo id tempora perspiciatis non doloribus natus nisi asperiores quia error autem laudantium, amet doloremque, vitae quos. Soluta unde numquam id.</p>
    <p>Recusandae facere esse quod dolorum maxime corrupti ex quam iure id quis eius cumque fugiat, consequatur autem, excepturi molestias libero velit illo a quo. Sed quae aut inventore quia, ipsa.</p>
    <p>Eius id laboriosam, quas iure laborum corrupti optio corporis tempore odit laudantium similique, accusamus, vel! Perspiciatis sed saepe rem. Nihil explicabo ea at vitae rerum eum, corrupti ipsam suscipit, id!</p>
    <p>Voluptate pariatur, cum praesentium, veniam tenetur distinctio totam voluptates ea beatae, dicta voluptatum illum sit! Earum harum odio natus perspiciatis. Magni eos temporibus harum quas laborum aspernatur, minus, sunt illum.</p>
    <p>Ducimus nobis, libero illum commodi aliquid. Molestias beatae ducimus ratione quod, quis itaque ipsum, illum amet labore, nostrum quisquam enim. Sint aperiam qui nihil eaque id quam odio? Repudiandae, sint!</p>
    <p>In rem tenetur accusamus accusantium id, officia quaerat atque, placeat architecto nihil unde, sit cupiditate minima tempore! Magni, atque labore. Dolor voluptatum eius incidunt, enim? Asperiores similique, ut amet atque?</p>
    <p>Illum, quam fugiat, veniam officia totam nihil aut dolore quo! Officiis ipsa harum vero voluptatibus eaque repudiandae amet eligendi ducimus laboriosam ab maiores labore, odit, voluptas quos illo sint nulla.</p>
    <p>Eius earum nihil officiis, inventore accusantium consequuntur dolor reprehenderit in esse quos eos iste nemo amet facere, mollitia, assumenda cum provident quam. Ipsam, vitae! Excepturi quos possimus enim, quia distinctio.</p>
    <p>Lorem ipsum, dolor, sit amet consectetur adipisicing elit. Commodi eaque, ipsa voluptate quia deserunt mollitia pariatur harum, vero temporibus dolores, quibusdam rem provident sint? Architecto sequi, quasi sunt neque recusandae.</p>
  </article>
</main>
<div id="screensaver" popover>
  <div class="dvd">
    <div class="dvd__scale">
      <div class="dvd__slide">
        <svg xmlns="http://www.w3.org/2000/svg" viewbox="8 44 178 104">
          <g fill-rule="evenodd" clip-rule="evenodd">
            <path d="M108.605 58.081c1.766-2.129 11.285-13.399 11.285-13.399h35.936c18.197 0 30.922 9.53 28.012 21.776-2.906 12.247-20.248 21.778-38.359 21.778h-24.09l7.227-30.422H145.6l-4.949 20.833h3.812c10.139 0 19.738-3.697 21.756-12.189 1.854-7.798-4.873-12.188-15.791-12.188h-3.984l-16.529.014-39.02 44.041-15.324-43.274s-.112-.276-.254-.649c-.035-.089-.328-.397-.485-.338-.286.106-.24.603-.19.711.125.266.162.367.196.497 1.368 3.34 1.446 8.946.89 11.187-3.031 12.218-20.25 21.778-38.359 21.778h-24.09l7.228-30.422H37.49l-4.949 20.833h3.812c10.138 0 19.682-3.697 21.699-12.189 1.852-7.798-4.817-12.188-15.734-12.188h-3.985l-16.983-.008 2.277-9.58H46.13l29.846-.039v.039h12.289s3.469 10.161 4.545 13.236c5.149 14.707 4.297 15.702 4.297 15.702s-.619-.949 11.498-15.54zM8.504 110.273c0-6.496 37.163-11.762 83.001-11.762 45.841 0 83.001 5.266 83.001 11.762 0 6.498-37.16 11.764-83.001 11.764-45.838 0-83.001-5.266-83.001-11.764zm79.997 4.153c10.47 0 18.954-1.754 18.954-3.922 0-2.164-8.484-3.92-18.954-3.92-10.467 0-18.952 1.756-18.952 3.92 0 2.168 8.485 3.922 18.952 3.922zm79.655 5.232h-.765l-.336 2.377h-.371l.332-2.377h-.764l.047-.338h1.902l-.045.338zm2.815 2.377h-.358v-2.058h-.008l-1.091 2.058-.469-2.078h-.008l-.67 2.078h-.357l.894-2.715h.311l.422 1.84.976-1.84h.358v2.715zM36.536 142.711h.062l5.119-10.32h4.816l-8.93 15.722h-2.622l-8.777-15.722h4.816l5.516 10.32zm25.447 4.996h-4.481v-15.316h4.481v15.316zm13.01-15.316h6.399c6.645 0 11.095 3.311 11.095 7.678 0 4.307-4.573 7.639-11.125 7.639h-6.37v-15.317h.001zm4.479 12.714h.731c5.517 0 7.651-2.031 7.651-5.059 0-3.33-2.562-5.057-7.651-5.057h-.731v10.116zm29.442-10.115v3.371h7.131v2.604h-7.131v4.14h7.406v2.602h-11.886v-15.316h11.886v2.599h-7.406zm19.041 5.037c0-4.287 4.662-8.045 11.367-8.045 6.703 0 11.369 3.758 11.369 8.045 0 4.387-4.666 8.086-11.369 8.086-6.705 0-11.367-3.699-11.367-8.086zm4.633-.119c0 2.312 2.926 5.26 6.734 5.26s6.734-2.947 6.734-5.26c0-2.479-2.803-4.979-6.734-4.979-3.933.001-6.734 2.501-6.734 4.979z"></path>
          </g>
        </svg>
      </div>
    </div>
  </div>
</div>
              
            
!

CSS

              
                @layer demo {
  .dvd__scale {
    position: fixed;
    top: 0;
    left: 0;
    animation: dvd-scale calc(var(--duration) * 1s) calc(var(--delay) * -1s)
      infinite linear alternate;
    /*
		For debugging the corner
		animation-duration: 4s;
		animation-delay: 0s;
	*/
  }

  .dvd__slide {
    animation: dvd-slide calc(var(--duration) * 1s) calc(var(--delay) * -1s)
      infinite linear alternate;
    /*
		For debugging the corner
		animation-duration: 4s;
		animation-delay: 0s;
	*/
  }

  #screensaver::backdrop {
    background: hsl(0 0% 20% / 0.5);
    backdrop-filter: blur(2px);
  }

  .dvd svg {
    fill: hsl(var(--hue, 0) 80% 50%);
    stroke: none;
    width: clamp(2rem, 20vmin, 10rem);
  }

  @keyframes dvd-scale {
    to {
      transform: translateY(calc(100vh - 100%));
    }
  }

  @keyframes dvd-slide {
    to {
      transform: translateX(calc(100vw - 100%));
    }
  }
}

@layer base {
  *,
  *:after,
  *:before {
    box-sizing: border-box;
  }

  body {
    display: block;
    min-height: 100vh;
    font-family: "Google Sans", sans-serif, system-ui;
    overflow: auto;
  }

  :where([popover]) {
    margin: auto;
    border-width: 0;
    border-style: none;
    background: transparent;
  }

  h1 {
    margin: 0;
    color: var(--gray-0);
  }

  header {
    height: 35vmin;
    min-height: 200px;
    background: var(--gradient-16);
    display: grid;
    place-items: center;
    color: var(--gray-0);
    padding: var(--size-4);
    grid-template-columns: 1fr;
  }

  h1 {
    background: var(--gradient-18);
    background-clip: text;
    -webkit-background-clip: text;
    background-attachment: fixed;
    color: transparent;
    font-size: var(--font-size-fluid-3);
  }

  main {
    margin: 0 auto;
  }

  article {
    padding: var(--size-4);
    display: flex;
    flex-direction: column;
    align-items: center;
  }

  article > * + * {
    margin-top: var(--size-4);
  }

  /* Inactivity ring */
  .inactivity-ring {
    fill: none;
    position: fixed;
    top: var(--size-4);
    right: var(--size-4);
    color: var(--teal-6);
    width: 40px;
    aspect-ratio: 1;
    stroke-dasharray: 130;
    stroke-dashoffset: 130;
    transform: rotate(-90deg);
    z-index: 20;
  }

  .inactivity-ring circle {
    stroke: currentColor;
  }

  .timing .inactivity-ring {
    animation: load calc(var(--threshold) * 1ms) linear;
  }

  @keyframes load {
    to {
      stroke-dashoffset: 0;
    }
  }
}

              
            
!

JS

              
                const randomInRange = (min, max) =>
  Math.floor(
    Math.random() * (Math.floor(max) - Math.ceil(min) + 1) + Math.ceil(min)
  );

const POPUP = document.querySelector("#screensaver");
const RING = document.querySelector("svg");
const SCALE = document.querySelector(".dvd__scale");
const SLIDE = document.querySelector(".dvd__slide");
const DVD = document.querySelector(".dvd");
const MOVERS = [SLIDE, SCALE];
const SCREENSAVER_THRESHOLD = 4000;
const BOUNCE_THRESHOLD = 2; // ms between bounces for a cheer. Ideal is 0 for a corner.

let checker;
let screensaverTimeout;
const EVENT_TYPES = [
  "pointermove",
  "keypress",
  "keydown",
  "keyup",
  "scroll",
  "click"
];

const setSaverTimer = () => {
  if (screensaverTimeout) {
    clearTimeout(screensaverTimeout);
    document.body.classList.remove("timing");
  }

  if (!POPUP.matches(":open")) {
    screensaverTimeout = setTimeout(() => {
      document.body.classList.remove("timing");
      POPUP.showPopover();
    }, SCREENSAVER_THRESHOLD);
    requestAnimationFrame(() => {
      document.body.classList.add("timing");
    });
  }
};

const BOUNCES = {
  dvd__scale: 0,
  dvd__slide: 0
};

const CHEER = new Audio(
  "https://assets.codepen.io/605876/grunt-party--optimised.mp3"
);

const handleBounce = (e) => {
  BOUNCES[e.target.className] = Date.now();
  DVD.style.setProperty("--hue", randomInRange(0, 359));
  const diff = Math.abs(BOUNCES.dvd__scale - BOUNCES.dvd__slide);
  if (diff <= BOUNCE_THRESHOLD) CHEER.play();
};

POPUP.addEventListener("beforetoggle", ({ newState }) => {
  if (newState === "closed") {
    setSaverTimer();
  } else {
    DVD.style.setProperty("--hue", randomInRange(0, 359));
    MOVERS.forEach((el) => {
      const duration = randomInRange(2, 6);
      el.style = `
        --duration: ${duration};
        --delay: ${duration * Math.random()};
      `;
    });
  }
});

MOVERS.forEach((mover) =>
  mover.addEventListener("animationiteration", handleBounce)
);

EVENT_TYPES.forEach((e) => document.body.addEventListener(e, setSaverTimer));

document.body.classList.add("timing");
document.documentElement.style.setProperty(
  "--threshold",
  SCREENSAVER_THRESHOLD
);
setSaverTimer();

              
            
!
999px

Console