Circular Text
3D Rotating circular text.
Demo
<script lang="ts"> import * as Null from "#lib/index.js"; </script> <Null.CircularText text={"Null — Null — Null —"} size={32} radius={26} />
CircularText.svelte
<script lang="ts"> import type { Snippet } from "svelte"; let { text = "", size = 160, radius = 64, duration = 12, reverse = false, pauseOnHover = true, children, }: { text?: string; size?: number; radius?: number; duration?: number; reverse?: boolean; pauseOnHover?: boolean; children?: Snippet; } = $props(); const id = $props.id(); const pathId = `circle-${id}`; </script> <div class="circular-text" class:reverse class:pause-on-hover={pauseOnHover} style={`--duration: ${Math.max(0.1, duration)}s; width: ${size}px; height: ${size}px;`} > <svg viewBox={`0 0 ${size} ${size}`} role="img" aria-label={text}> <defs> <path id={pathId} d={`M ${size / 2},${size / 2} m -${radius},0 a ${radius},${radius} 0 1,1 ${radius * 2},0 a ${radius},${radius} 0 1,1 -${radius * 2},0`} /> </defs> <text> <textPath href={`#${pathId}`} startOffset="0%"> {text} </textPath> </text> </svg> {#if children} <div class="center"> {@render children()} </div> {/if} </div> <style> .circular-text { position: relative; display: grid; place-items: center; color: currentColor; } svg { width: 100%; height: 100%; overflow: visible; animation: spin var(--duration) linear infinite; } text { fill: currentColor; font-size: 10px; font-weight: 600; letter-spacing: 2px; text-transform: uppercase; } .reverse svg { animation-direction: reverse; } .pause-on-hover:hover svg { animation-play-state: paused; } .center { position: absolute; inset: 25%; display: grid; place-items: center; text-align: center; } @keyframes spin { to { transform: rotate(360deg); } } @media (prefers-reduced-motion: reduce) { svg { animation-play-state: paused; } } </style>