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-screensaver for playful motion and kiosk-style idle states.
  • - analog-clock-screensaver for calm, full-screen ambient displays.
  • - sleeping-cat-screensaver for 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.json

You 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:

  1. - Track mouse, keyboard, or touch activity.
  2. - Reset a timer whenever the user interacts.
  3. - Show the screensaver after a period of inactivity.
  4. - 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:

  • - text changes the main wordmark.
  • - subText controls the smaller label.
  • - speed adjusts how fast the logo moves.
  • - className lets 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:

  • - title sets the label below the clock.
  • - accentColor changes the second hand and center dot.
  • - backgroundClassName changes the fullscreen background style.
  • - className adds 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:

  • - bgColor changes the background.
  • - brandText updates the label.
  • - imageSrc replaces the cat image.
  • - imageAlt changes 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.
  1. - Pick one screensaver based on the mood you want.
  2. - Install it with the shadcn CLI.
  3. - Decide when it should appear: idle timeout, route, kiosk mode, or manual trigger.
  4. - Mount it in a fullscreen overlay or dedicated route.
  5. - 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.