050

Ambient Orb Field

£10 or the whole Vault, £99

Six luminous colour orbs stay distinct as they drift and lean with the pointer, then rack into crisp blend-mode discs when you press and hold.

intermediate
6 more details
ambientblend-modefilterorganic-motionpointer-effectsprogressive-enhancement

This demo reads better at your own screen size than in the frame below:

Updated

About this effect

A bold background field built from six ordinary elements, a CSS blur and a blend mode. Each orb answers the pointer by an amount set by its depth, so moving across the page slides the near planes further than the far ones and the flat wash resolves into a stack. The orbs also drift on three unrelated loops each, so the composition never visibly repeats.

Read the full effect overview

The whole field is a lens: press and hold and the blur racks down until the blooms become hard-edged discs with every blend intersection visible, while the copy in front softens the way a real focus pull trades one plane for another. A scrim layer keeps overlaid headlines and buttons at full contrast over the brightest part of the field, and one attribute swaps the same six orbs between a pale surface and a dark one.

Ambient Orb Field - GSAP animation effect preview

What's included

10 items
  • Six large soft orbs from six plain elements, no canvas and no WebGL
  • Depth-weighted pointer follow: near planes travel roughly twice as far as far ones, on a 0.34s weighted ease
  • Press-and-hold focus rack: blur, saturation, orb scale and a depth-of-field softening of the overlaid copy on one input
  • Blooming settle that overshoots past rest on both blur and scale before relaxing
  • Three unrelated drift loops per orb so the field never visibly repeats
  • Pale and dark surfaces from one attribute, swapping the blend mode between multiply and screen
  • Contrast scrim layer that keeps overlaid headings and buttons readable over the brightest blooms
  • Whole-page mode that pins the field to the viewport so content scrolls over a stationary ground
  • Motion is transforms and opacity only, so the expensive blur is a static texture the compositor reuses
  • Complete static composition without JavaScript and under reduced motion

Perfect for

5 use cases
  • SaaS and product landing hero sections that need depth without a photograph
  • Pricing, feature and sign-up bands that would otherwise read flat
  • App marketing pages where the background must never compete with the copy
  • Documentation and dashboard shells that want atmosphere behind a calm interface
  • Any section that has to sit on both a dark and a pale ground

How it works

3 sections

Each orb is an absolutely positioned element carrying a radial-gradient core, a CSS blend mode and a blur filter whose radius is one custom property on the parent. Ambient drift is three tweens per orb on position and opacity with deliberately unrelated durations.

The pointer follow is written as a percentage so it composes with the drift inside a single transform. Travel is authored in pixels and converted per orb from its own width, and each orb's share is weighted by its depth attribute, which is what turns one pointer position into a stack of planes rather than one sliding picture.

A press starts a timeline that writes the blur radius, saturation and the overlaid content's own blur back as custom properties, while a parallel tween scales the orbs. Releasing runs the same timeline with a deliberate overshoot past rest on both channels so the field blooms open rather than snapping. The pre-script paint is the soft resting field, so the page is complete and readable with JavaScript disabled.

Difficulty Intermediate
Includes HTML + JS + CSS source, documentation, AI setup prompt, lifetime updates

Lighthouse, as measured

Google Lighthouse on this effect's demo, from the latest scan. A measurement of the demo as shipped, not a promise for your page.

Accessibility
100
Best practices
100

No performance score, on purpose. That figure depends on how you deploy: your server's compression and caching, your CDN, the connection and the device doing the test, none of which the code controls. The same page can score very differently on two consecutive runs, so measure it where it will live.

Paid effect

Purchase to unlock the code.

Buying Ambient Orb Field opens the HTML, CSS and JavaScript source, the full documentation, an AI setup prompt for your editor, and every update we ship to it. Standard license: unlimited personal and commercial projects. Every paid product is tested for desktop and mobile layouts, reduced-motion handling, animation cleanup and keyboard controls wherever there is something to operate.

£10 Standard license, unlimited projects

Browse free effects

Or the whole library: the Vault, £99, one payment.

Documentation

Quick Start

1. Add to your HTML <head>:

Code snippet omitted: it ships with the download.

2. Add the section to your <body>:

Code snippet omitted: it ships with the download.

3. Add before the closing </body> tag:

Code snippet omitted: it ships with the download.

The script finds every [data-orb-field], gives each [data-orb] inside it three drift loops and a depth-weighted pointer follow, and wires the press-and-hold focus rack.

Using It With Your Own Design

The effect asks for four things and ignores everything else.

  1. A stacking context on the section. [data-orb-field] is position: relative, overflow: hidden and, critically, isolation: isolate. mix-blend-mode blends against the nearest stacking context, so without isolation: isolate the orbs blend with your whole page instead of this section's own background. This is the single most common way the effect "stops working" when it is dropped into a real layout.

  2. Orbs as [data-orb] elements. Each one is positioned by four custom properties you set inline: --orb-x, --orb-y (the centre, as a percentage of the section), --orb-size (diameter, as a percentage of the section's width) and --orb-color. data-orb-depth is optional and only weights the drift distance and the pointer follow. Spread your depths out: orbs that all answer the pointer by the same amount read as one sliding picture rather than as separate planes. script.js never looks at a class name.

  3. The .orb-scrim layer. It is a directional wash in the ground colour sitting between the orbs and the content. It is what keeps a white headline at AA contrast when a bright orb drifts under it. Delete it and the effect will eventually make some piece of your copy unreadable. Tune --field-scrim rather than removing it.

  4. data-orb-content on the element you want the depth-of-field applied to. This is the copy that softens while the field is racked into focus. It is optional; leave it off and the content stays sharp throughout. Whatever carries it needs position: relative and a z-index above the scrim, which the supplied CSS does.

Room to move. The orbs travel a real distance under the pointer, so keep the important ones inset from the edges. The demo deliberately crops two edge orbs for scale, while the central orbs retain enough margin to stay visible throughout their travel.

Using it as a whole page's ground. Add data-orb-fixed to the field and put your entire page inside it. The orb layer and the scrim switch to position: fixed, so content scrolls over a stationary field instead of the field scrolling away with the first section. The demo does not need it because it is a single screen, but any page taller than the viewport will.

Everything else in style.css below the DEMO CONTENT comment is the demo's page styling and can be deleted.

Blur radius and orb size are one decision, not two. Past roughly 0.6 of an orb's diameter the blooms merge into a single continuous wash and the field stops reading as separate objects, which is the whole point of this effect over a gradient. The demo uses a 26px blur against orbs 24–40% wide, keeping every orb legible even before the focus rack. If you scale the orbs up, scale --orb-blur-rest with them.

Options

Set on [data-orb-field]:

Attribute Values Default Description
data-orb-field marker required Identifies a field
data-orb-ground dark, light dark Which surface the field sits on. Swaps the blend mode between screen and multiply along with the ground and ink colours
data-orb-blur pixels --orb-blur-rest Resting blur radius. Defaults to the CSS value, so the viewport media queries stay the single source
data-orb-focus-blur pixels --orb-blur-focus Blur radius at full focus
data-orb-content-blur pixels 1.5 How far the [data-orb-content] copy softens while focused. 0 disables it
data-orb-drift 0–3 1 Multiplier on how far the orbs travel. 0 freezes them
data-orb-parallax pixels 220 How far a nearest-plane orb travels across the full width of the field as the pointer crosses it. 0 disables the follow. Never applied on a coarse pointer or under reduced motion
data-orb-fixed marker off Pins the orb layer and the scrim to the viewport so the field can be a whole page's ground
data-orb-intro false on Set to false to skip the opening rack-out and start at rest

Set on each [data-orb]:

Attribute Values Default Description
data-orb-depth 0–1 0.5 Weights drift distance and pointer travel. Higher travels further
--orb-x, --orb-y percentage required Centre of the orb within the section
--orb-size percentage required Diameter, as a percentage of the section's width
--orb-color colour required The orb's core colour

Set on any button, anywhere on the page:

Attribute Values Description
data-orb-focus marker Toggles the focus rack and latches it. aria-pressed is managed for you
data-orb-ground-control dark, light Switches the surface. aria-pressed is managed for you

Both resolve to the field named by their aria-controls, or to every field if that attribute is absent.

How It Works

Each orb is one element with a radial-gradient core, a mix-blend-mode and filter: blur(var(--orb-blur)). Because the radius is a single custom property on the parent, one write re-blurs the whole field.

Ambient drift is three GSAP tweens per orb, on x, y and opacity, with durations chosen never to line up. Nothing in the idle loop touches the filter, so the expensive rasterisation happens once and the drift stays on the compositor.

The pointer follow runs through gsap.quickTo on xPercent/yPercent, which composes with the drift's x/y inside the same transform instead of fighting it. Travel is authored in pixels and converted per orb from its measured width, because the orbs are deliberately different sizes and a share of each orb's own width would leave the small ones looking stuck. Each orb's share of the full travel is set by its depth, and the follow is a 0.34s power2.out ease: quick enough that the field is clearly answering the pointer, slow enough that it arrives with weight rather than snapping to the cursor.

A press starts a GSAP timeline over a plain state object. Its onUpdate writes the blur radius, the saturation and the content's own blur back as custom properties; a parallel tween scales the orbs down as they sharpen, which is what a real lens does. The release leg overshoots past the resting blur and past scale 1 before relaxing, so the field blooms open instead of snapping shut.

Accessibility

  • Reduced motion: no drift, no pointer follow and no opening rack. The field is a composed static backdrop, and the focus rack still works if a control is pressed, applied instantly rather than animated.
  • No JavaScript: the pre-script paint is the resting field. Every orb, the scrim and all content are visible and readable with scripting off; nothing is hidden waiting for a class.
  • Keyboard: [data-orb-focus] is a real <button> with a managed aria-pressed, giving keyboard users the same rack the pointer gets. A press that lands on a link, button or form control does not start a rack, so the gesture never competes with the controls sitting on the field. The orb layer and scrim are aria-hidden and pointer-events: none, so links and buttons inside the section keep their focus styles.
  • Contrast: the scrim exists for this. Check your headline against the brightest point of your palette, not against the ground colour, and raise the scrim's alpha rather than dimming the orbs.
  • Content blur: the depth-of-field softening of the copy is transient and only ever the visitor's own doing. Set data-orb-content-blur="0" if any of that copy is essential.

Performance Notes

  • Large blur radii are expensive to rasterise, so the effect only animates the blur during a rack. Idle motion is transform and opacity, which stays on the compositor.
  • Six orbs is a deliberate ceiling. Every additional orb is another large blurred layer to composite; twenty of them is a different, much slower effect.
  • Mobile reduces both the resting blur and the focus blur while spreading the orbs wider, so the field reads the same at a fraction of the fill rate.
  • The pointer follow is transform only. The blur radius never changes while an orb is moving, so the browser reuses one blurred texture per orb and the follow costs a composite, not a re-rasterise, however far the orbs travel.
  • will-change: transform promotes the orbs once. Adding will-change: filter is tempting and usually makes it worse: it holds a full-size blurred texture per orb for the whole session.

Dependencies

Required:

  • GSAP 3.12+

No plugins.

Worked examples, the events and programmatic API, and the class reference ship with the download, alongside the full source.