Screensavers
How to apply screensaver components to your project.
Screensavers are not typical UI blocks. They work best when you treat them like a deliberate state in your product instead of a decorative effect you keep on all the time.
The Refinery screensaver set includes three ready-to-install components:
- -
dvd-screensaverfor playful motion and kiosk-style idle states. - -
analog-clock-screensaverfor calm, full-screen ambient displays. - -
sleeping-cat-screensaverfor a softer, more playful idle view.
The install flow is simple: add the component with the shadcn CLI, import it into your app, and decide when the screensaver should appear. The important part is the product logic around activation, dismissal, motion preference, and layout.
Install a screensaver component
Use the full registry URL or your @refinery alias if you already configured it.
npx shadcn@latest add https://refinery.abhii.me/r/dvd-screensaver.jsonYou can swap dvd-screensaver for analog-clock-screensaver or sleeping-cat-screensaver.
After installation, import the component from wherever shadcn placed it in your project:
import DVDScreensaver from "@/components/dvd-screensaver";How to apply a screensaver
The main pattern is to mount the screensaver only when your app is in a special state. Common triggers are:
- - User inactivity for a certain amount of time.
- - A dedicated kiosk or display mode.
- - A loading or waiting screen that should feel intentional.
- - A route or section meant to be immersive rather than task-driven.
For most websites, a screensaver should not replace the entire app permanently. Use it as an overlay, a fullscreen mode, or a conditional route. That keeps the rest of the site usable and prevents the screensaver from interfering with normal navigation.
A simple inactivity toggle
The usual implementation is:
- - Track mouse, keyboard, or touch activity.
- - Reset a timer whenever the user interacts.
- - Show the screensaver after a period of inactivity.
- - Hide it again when the user moves, clicks, or presses a key.
"use client";
import { useEffect, useState } from "react";
import DVDScreensaver from "@/components/dvd-screensaver";
export default function IdleGate() {
const [showSaver, setShowSaver] = useState(false);
useEffect(() => {
const prefersReducedMotion = window.matchMedia(
"(prefers-reduced-motion: reduce)"
).matches;
if (prefersReducedMotion) return;
let timeoutId: ReturnType<typeof setTimeout>;
const resetIdleTimer = () => {
setShowSaver(false);
clearTimeout(timeoutId);
timeoutId = setTimeout(() => setShowSaver(true), 60_000);
};
const events = [
"pointermove",
"keydown",
"mousedown",
"touchstart",
"scroll",
] as const;
resetIdleTimer();
events.forEach((eventName) => window.addEventListener(eventName, resetIdleTimer));
return () => {
clearTimeout(timeoutId);
events.forEach((eventName) => window.removeEventListener(eventName, resetIdleTimer));
};
}, []);
return showSaver ? <DVDScreensaver /> : null;
}That pattern works well for the DVD saver because the component already handles movement and pausing. The screensaver itself should be the presentation layer; your app should decide when it appears.
Fullscreen overlay pattern
If you want the screensaver to cover a page, render it in a fixed overlay and keep the app beneath it:
{showSaver && (
<div className="fixed inset-0 z-50">
<DVDScreensaver />
</div>
)}This is the easiest approach for dashboards, kiosks, and museum-style displays where the screensaver takes over the whole viewport.
If the overlay should be dismissed immediately on interaction, put the idle reset listener in the app shell as shown above instead of inside the screensaver component. That keeps the component reusable and leaves product behavior in one place.
Section-based pattern
For landing pages or product demos, you can place a screensaver inside a dedicated section instead of using it as an overlay. In that case, give the wrapper a fixed height and let the component fill the space.
<section className="h-128 overflow-hidden rounded-3xl border border-neutral-200 dark:border-neutral-800">
<AnalogClockScreensaver title="Refinery" />
</section>Component-by-component guidance
dvd-screensaver
This one feels the most like a classic idle screen. Use it when you want movement, color changes, and a little nostalgia.
Props:
- -
textchanges the main wordmark. - -
subTextcontrols the smaller label. - -
speedadjusts how fast the logo moves. - -
classNamelets you size or position the wrapper.
Good uses:
- - Kiosk idle state.
- - TV or display screen.
- - Fun product waiting screen.
Tip: the component is clickable and pauses on interaction, which makes it a good choice when you want a screensaver that feels alive but still controllable.
analog-clock-screensaver
This is the calmest option. It works well when the screensaver should feel ambient, minimal, or time-based.
Props:
- -
titlesets the label below the clock. - -
accentColorchanges the second hand and center dot. - -
backgroundClassNamechanges the fullscreen background style. - -
classNameadds extra wrapper styling.
Good uses:
- - Office displays.
- - Waiting rooms.
- - A dark, polished idle mode.
Tip: the component is already fullscreen by default, so it is usually best placed as a route-level view or a page takeover. If you render it inside a smaller section, give the parent a fixed height and hide overflow so the clock stays framed.
sleeping-cat-screensaver
This one is the most playful. It works well for friendly products, playful brands, or personal projects that want a softer idle state.
Props:
- -
bgColorchanges the background. - -
brandTextupdates the label. - -
imageSrcreplaces the cat image. - -
imageAltchanges the image alt text.
Good uses:
- - Empty states with personality.
- - User-inactivity fallback screens.
- - A lightweight break screen for casual apps.
Tip: because it uses an image and gentle animation, it is a good fit when you want motion without the energy of the DVD version.
Design rules that keep it usable
- - Keep the screensaver hidden until it has a purpose.
- - Make it easy to dismiss with pointer movement, keyboard input, scrolling, or a tap.
- - If it covers the app, restore the previous UI state when the user returns.
- - Do not use it as decoration on every page. It should feel intentional.
- - Respect reduced-motion preferences before showing an automatically animated idle state.
- - Keep route-level screensavers client-rendered when they depend on timers, browser events, or the current time.
Recommended implementation flow
- - Pick one screensaver based on the mood you want.
- - Install it with the shadcn CLI.
- - Decide when it should appear: idle timeout, route, kiosk mode, or manual trigger.
- - Mount it in a fullscreen overlay or dedicated route.
- - Dismiss it on user interaction and return to the last useful screen.
If you are adding screensavers to a real product, start with dvd-screensaver for playful apps, analog-clock-screensaver for calm utility screens, and sleeping-cat-screensaver for softer brands. The component install is the easy part; the UX rule is to treat the screensaver like an idle state, not a background effect.