Atmosphere✨ Premium

WebGPU Spirit Vortex

Fourteen thousand spirits drift in an open field and spiral inward around the cursor as if a portal were opening — 2D canvas fallback if WebGPU is absent.

WebGPUWGSLVortex

Updated

This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. Atmosphere has 58 effects, including 10 free. Explore the category →

3 usage examples

Interactive hero for a nocturnal or mystical event — WebGPU Spirit Vortex example 1

① Interactive hero for a nocturnal or mystical event

WhenA festival, escape room or narrative experience landing page wants to capture attention before any text — the interaction should be discoverable without instructions.
WhyThe vortex forms wherever the cursor passes: the first few seconds of exploration trigger the effect. Visitors understand within moments that they are 'summoning' something, which fits a mystical event's atmosphere exactly. The floating ambient field without interaction remains readable for keyboard users.
SettingsRemove the [data-sws-tag] badge on a consumer site. Layer the event title and CTA at a high z-index with a dark centred radial gradient to keep text legible.
Legendary card reveal screen in a digital card game — WebGPU Spirit Vortex example 2

② Legendary card reveal screen in a digital card game

WhenA player just opened a pack and pulled a legendary card: the interface shows a full-screen dramatic reveal before returning to the collection. The effect replaces a static background or a pre-rendered video.
WhyThe vortex responds to the cursor in real time: the player "summons" the spirits by exploring the screen, reinforcing the sense of power tied to a rare card. The teal-to-violet palette fits heroic-fantasy and dark-magic design systems. The animation is pure CSS+JS — no video file to load.
SettingsLayer the card name and stats at z-index: 2 with pointer-events: none so the cursor passes through and reaches the scene. Adjust N for the target: 14,000 on desktop, 6,000 on mobile.
Background for a call-to-action section on a premium service — WebGPU Spirit Vortex example 3

③ Background for a call-to-action section on a premium service

WhenA conversion section (subscription, sign-up, exclusive access) wants to stand out from the rest of the page with an animated, interactive background that visually justifies the idea of a 'restricted zone'.
WhyThe vortex responds as the cursor approaches the CTA button, creating a natural visual tension just before the click. The ambient floating background (without cursor) stays understated and does not compete with the text. The teal-to-violet palette stands out against most dark brand palettes.
SettingsCover the scene with a background: linear-gradient(to bottom, transparent, rgba(4,6,10,.85)) at z-index: 1 to soften the transition to adjacent sections. Position the CTA button at z-index: 2 in the bottom centre.

How it works

Fourteen thousand seeds are drawn once into a Float32Array: two random numbers per particle, unchanged for the life of the page. Each particle's ambient state is computed every frame from its seed and time: a slow drift angle (a0 + t × (0.08 + r × 0.25)), radius kept at 92 % to avoid overly eccentric orbits. No position array to maintain.

When the cursor is inside the scene, its normalised coordinates (mx, my in clip space, corrected for aspect ratio) are sent to the WGSL shader every frame via the uniform buffer. The shader computes the distance d from the particle's ambient position to the cursor, then an attraction factor k = clamp(0.7 / (d + 0.5), 0, 0.85): zero far away, strong but never total close up. The particle is interpolated between its ambient position and a point on a spiral centred on the cursor — tangential angle atan2 + t × 1.7 − d × 2.6, radius progressively reduced towards a 0.06 core. Colour shifts from teal ((0.32, 0.85, 0.68)) to violet ((0.80, 0.68, 1.0)) with k.

At start-up the code follows exactly the same three-step cascade as WebGPU Particle Field (fx-0802): checking navigator.gpu, obtaining an adapter and device, confirming the webgpu context responds. Any failure, like any exception, switches to the 2D canvas engine, which reproduces the same attraction logic in JavaScript — same render, same interaction, fewer particles.

Accessibility

  • Under prefers-reduced-motion: reduce, time is frozen at zero: particles stay still in their initial arrangement. Cursor interaction remains active (the code does not disable it), but since time does not advance, the spiral no longer rotates — the portal is open but static.
  • The canvas carries no information: it is decoration. The mode badge [data-sws-tag] is marked aria-hidden="true".
  • The 2D canvas fallback is visually complete: a visitor without WebGPU sees the same interactive vortex, with fewer particles. The degradation is in density, never in the presence or interactivity of the effect.
  • The crosshair cursor on the scene signals interactivity without needing extra text or a label.
  • devicePixelRatio is capped at 2 to maintain smoothness on very dense screens.

Browser compatibility

WebGPU (navigator.gpu, WGSL shader, 4 uniform floats) with a full 2D canvas fallback, plus requestAnimationFrame, matchMedia, devicePixelRatio and PointerEvent. No library.

Chrome 113+✓ WebGPU + interaction
Edge 113+✓ WebGPU + interaction
Safari 26+✓ WebGPU + interaction
Firefox 141+ (Windows)✓ WebGPU — 2D canvas fallback elsewhere
Safari iOS 26+✓ WebGPU + interaction
Any other browser✓ 2D canvas fallback — same render and interaction, fewer particles

The 2D canvas fallback covers all three WebGPU failure cases: no navigator.gpu, adapter or device refused, failing webgpu context. Without JavaScript, the canvas stays empty: give .sws-scene a background colour. Without PointerEvent, particles drift without interaction (very old browser).

The code

HTML structure to paste into your page (the CSS + JS come with your purchase):

index.html — structure
<div class="sws-scene" data-sws>
  <!-- The canvas is sized by the script, never hard-coded -->
  <canvas class="sws-canvas" width="0" height="0"></canvas>

  <!-- Mode badge: the script writes "WebGPU active" or "Canvas 2D (fallback)" here.
       Useful in development; drop it in production if it no longer serves. -->
  <div class="sws-tag" data-sws-tag aria-hidden="true">Canvas 2D (fallback)</div>
</div>

One-time payment, no subscription — the code is yours forever

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
N — particle count 14000 On WebGPU, 14,000 is comfortable and 80,000 stays workable on a discrete card. On the 2D canvas fallback, come down to around 4,000: cost there is per particle, not per frame.
Portal strength 0.7 / (d + 0.5), capped at 0.85 Raising the numerator (e.g. 1.2) strengthens the pull and broadens the zone of influence. Raising the denominator (e.g. 1.0) gives a gentler portal that only forms when the cursor is very close.
Ambient drift speed 0.08 + radius × 0.25 The 0.08 factor is the minimum speed at the centre. The 0.25 factor differentiates centre from rim (slow to fast rotation). Lowering both gives a nearly static field, almost ghost-like.
Spiral speed and pitch angle t × 1.7 − d × 2.6 The 1.7 coefficient sets the portal's rotation speed. The 2.6 coefficient controls the arm winding: a higher value makes close particles form a tighter spiral.
Convergence radius mix(d, 0.06, k) 0.06 is the portal's core radius in clip coordinates. A larger value (e.g. 0.15) gives an open portal with a visible eye; a smaller one (0.02) concentrates nearly all particles into a single point.
Palette teal (0.32, 0.85, 0.68) → violet (0.80, 0.68, 1.0) by k The two endpoints control the ambient colour (low k) and the portal colour (high k). For a Halloween mood, replace teal with a soft orange and violet with blood red.
devicePixelRatio cap 2 Sharpness / load trade-off. Do not raise it above 2: the visual gain on fine points is marginal and GPU load grows as the square.

FAQ

Each particle's position is recomputed every frame from its seed and time — not from its previous state. The shader first computes the ambient position, measures its distance to the cursor, then interpolates between that position and a point on the spiral. The effect is fully deterministic: two particles with the same seeds and the same cursor will always be at the same location.
The IIFE initialises every [data-sws] scene found in the document. Each scene has its own seeds, its own canvas and its own cursor tracking: the vortices are independent. On a scrolling page, an IntersectionObserver can be added to pause loops that are off screen.
Yes. The pointermove event also fires on touch on mobile. Dragging a finger across the scene opens the portal, and releasing (pointerleave) sends particles back to ambient drift. The default position [99, 99] (outside normalised clip space) disables attraction between interactions.