ShinyText

The ShinyText component adds an animated shimmer effect to text, creating an elegant and eye-catching visual element that’s perfect for headings, titles, or any text you want to emphasize with subtle movement.

Usage

<script>
  import ShinyText from "$lib/components/ui/ShinyText.svelte";
</script>

<ShinyText text="Magical Text" />

Examples

Basic ShinyText

A simple example with default styling.

magic.movmagic.mov

With Custom Text

ShinyText with different content.

Create Cinematic MagicCreate Cinematic Magic

With Custom Class

ShinyText with custom styling applied.

Experimental FilmsExperimental Films

Multiple Instances

Multiple ShinyText components showing different shimmer timings.

Meter MadnessMeter Madness
KinoScripterKinoScripter
Visual PoetryVisual Poetry

In Context

Using ShinyText within a UI component.

Welcome to magic.movWelcome to magic.mov

A collection of experimental filmmaking tools to enhance your creative process

API Reference

ShinyText Properties

PropertyTypeDefaultDescription
textstring''The text content to display with the shimmer effect.
classstring''Additional CSS classes to apply to the container element.

Implementation

The ShinyText component uses SVG and CSS animations to create a shimmering effect over text. It first renders the text normally, then creates an SVG mask of the text and applies a gradient animation that moves across the text creating the shimmer effect:

<script lang="ts">
	import { cn } from '$lib/utils';

	let { text = '', class: className = '' } = $props<{ text: string; class?: string }>();

	// Create unique IDs for our SVG elements
	const maskId = $state(crypto.randomUUID());
	const gradientId = $state(crypto.randomUUID());

	// Calculate text dimensions for proper shimmer
	let textElement: SVGTextElement;
	let textWidth = $state(0);
	let textHeight = $state(0);

	$effect(() => {
		if (textElement) {
			const bbox = textElement.getBBox();
			textWidth = bbox.width;
			textHeight = bbox.height;
		}
	});
</script>

<div class={cn('relative inline-block', className)}>
	<span class="invisible">{text}</span>
	<svg
		class="absolute inset-0 h-full w-full"
		preserveAspectRatio="xMidYMid slice"
		viewBox="0 0 {textWidth} {textHeight}"
	>
		<!-- Define the gradient for the shimmer effect -->
		<defs>
			<linearGradient id={gradientId} x1="0%" y1="0%" x2="100%" y2="0%">
				<stop offset="0%" stop-color="transparent" />
				<stop offset="45%" stop-color="transparent" />
				<stop offset="50%" stop-color="hsl(var(--blue-200))" stop-opacity="0.5" />
				<stop offset="55%" stop-color="transparent" />
				<stop offset="100%" stop-color="transparent" />
			</linearGradient>

			<!-- Create a mask from the text -->
			<mask id={maskId}>
				<text
					bind:this={textElement}
					x="50%"
					y="50%"
					text-anchor="middle"
					dominant-baseline="middle"
					class="font-grotesk fill-white text-4xl tracking-tight"
				>
					{text}
				</text>
			</mask>
		</defs>

		<!-- Base text layer -->
		<text
			x="50%"
			y="50%"
			text-anchor="middle"
			dominant-baseline="middle"
			class="font-grotesk fill-[hsl(var(--foreground))] text-4xl tracking-tight"
		>
			{text}
		</text>

		<!-- Animated shimmer layer -->
		<rect
			width="200%"
			height="100%"
			fill={`url(#${gradientId})`}
			mask={`url(#${maskId})`}
			class="animate-shimmer"
		/>
	</svg>
</div>

<style>
	@keyframes shimmer {
		0% {
			transform: translateX(-100%);
		}
		100% {
			transform: translateX(0%);
		}
	}

	.animate-shimmer {
		animation: shimmer 2.5s ease-in-out infinite;
	}
</style>

The component uses Svelte 5 Runes ($state, $effect, $props) for reactive state management, following the coding standards for magic.mov. The shimmer animation is created using CSS keyframes animation that moves a gradient across the text, which is applied using SVG masks to ensure it only appears on the text itself.