Skip to content
Effects Fancy Stable

PixelScene

.md

An animated pixel-art landscape on a dot grid: sparse ink dots at rest, full colour under a round lens that follows the pointer, separate day and night palettes, and on HDR displays lit windows, stars and the sun drawn as squares brighter than SDR white. Four scenes: alpine, meadow, sea and mountains.

Available for Svelte 5, React, and Vue 3.

Preview

Installation

pnpm add fancy-ui-svelte
import { PixelScene } from "fancy-ui-svelte";

Usage

svelte
<script lang="ts">
	import { PixelScene } from "fancy-ui-svelte";

	// The component never changes `night`: the page owns it. A click anywhere on the
	// picture flips it, and the button gives keyboard users the same switch.
	let night = $state(false);
</script>

<PixelScene
	scene="alpine"
	{night}
	onclick={() => (night = !night)}
	class="border-foreground/10 text-foreground h-[340px] w-full cursor-pointer rounded-2xl border"
>
	<div class="pointer-events-none absolute top-5 left-5 max-w-[460px] pr-5 sm:top-9 sm:left-9">
		<p class="text-muted-foreground font-mono text-[11px] tracking-[0.2em] uppercase">
			Season notes · {night ? "After dark" : "Morning"}
		</p>
		<h3 class="mt-2 text-3xl leading-tight font-semibold tracking-tight sm:text-4xl">
			First snow on the ridge
		</h3>
		<p class="text-muted-foreground mt-3 hidden max-w-sm text-sm leading-relaxed sm:block">
			Move across the picture to see it through the lens. Click anywhere to let the night fall.
		</p>
		<button
			type="button"
			aria-pressed={night}
			class="border-foreground/20 bg-background/70 hover:bg-background focus-visible:ring-ring pointer-events-auto mt-4 inline-flex items-center gap-2 rounded-full border px-3 py-1 text-xs font-medium backdrop-blur-sm transition-colors focus-visible:ring-2 focus-visible:outline-none"
			onclick={(event) => {
				event.stopPropagation();
				night = !night;
			}}
		>
			<span
				class="size-2 rounded-full {night ? 'bg-[#ffd15c]' : 'bg-foreground/30'}"
				aria-hidden="true"
			></span>
			Night
		</button>
	</div>
</PixelScene>

Examples

Basic Usage

Scenes

Alpine, meadow, sea and mountains, by day and by night.

Hours of low light

The scene owns its surface and ink, so a click carries the whole card on the wave. Opens on the sea at night; switch the HDR look to compare.

Interactive Playground

Props

PropTypeDefaultDescription
scene "alpine" | "meadow" | "sea" | "mountains""alpine"Which landscape to paint.
night booleanfalseNight palette: stars, moonlit snow, lit windows. The component never changes it; toggle it from your own click or theme.
cell number5Grid pitch in CSS pixels. Very large boxes use a coarser pitch so a frame stays under about 72 000 cells.
dot number4Edge of each square dot in CSS pixels (at most `cell`).
lens booleantrueShows the picture in full colour under a round lens that follows the pointer.
lensRadius number21Lens radius in cells. Its rim is dithered on the grid.
hdr booleantrueOn a display that reports HDR, redraws the sun, windows, stars and the lens in a WebGPU layer brighter than SDR white. Elsewhere nothing is created.
hdrLook "calibrated" | "vivid""calibrated"HDR rendering: calibrated levels (glow 1 is the SDR dot, sRGB), or vivid, a hotter, wider-gamut look (display-p3) with lamps at the panel peak.
ink string"currentColor"Colour of the resting dots outside the lens. Resolved on the host, so it follows the theme.
paused booleanfalseFreezes clouds, birds and lights; the lens still follows the pointer.
wave booleantruePlays a change of `night` as a dithered wave spreading from the sun (or moon), led by a halo that glows on HDR displays. Off under reduced motion.
surfaces readonly [day: string, night: string]—Background painted by the scene for each theme; the wave carries it from one to the other. Without it the canvas is transparent.
inks readonly [day: string, night: string]—Dot colour for each theme, swapped by the wave. Overrides `ink`.
class string-Additional classes on the host. Give it a height.

Slots

SlotDescription
children Copy rendered above the picture. Keep it in the top-left corner, which every scene leaves open.