Scroll-driven Page-building Effect with Animated Cursors – cursor-swarm.js

Category: Animation , Javascript | November 10, 2026
AuthorZhengLinLei
Last UpdateNovember 10, 2026
LicenseMIT
Views0 views
Scroll-driven Page-building Effect with Animated Cursors – cursor-swarm.js

cursor-swarm.js is a dependency-free JavaScript library that animates cursors building a web page as visitors scroll.

It draws boxes, types text, and reveals media on existing pages, with an optional reverse animation when visitors scroll up.

Features

  • 5 build animations for boxes, controls, headings, body text, and media.
  • Agent cursors share layout, typing, and media tasks.
  • A progress HUD, cursor labels, guide lines, and completion particles.
  • Optional copy-paste animations for repeated cards and UI elements.
  • Optional relocation animations that move elements into position.
  • Adaptive animation speed for rapid scrolling.
  • Per-element animation overrides through HTML attributes.
  • Built-in support for reduced-motion preferences.

How To Use It

Basic Usage

Place the core JavaScript before the closing body tag. By default, CursorSwarm scans document.body and animates elements as they enter the viewport.

<script src="cursor-swarm.js"></script>
<script>
  const swarm = new CursorSwarm({ cursors: 3 }).init();
</script>

Animate Only One Section

Set root to a section selector to animate part of the page. Add data-cs-ignore to elements that should be excluded.

<section id="feature-showcase">
  <h2>Build better workflows</h2>
  <p>Organize projects and share updates from one workspace.</p>
  <div style="padding: 24px; background: #f1f5f9; border: 1px solid #cbd5e1;">
    <h3>Project overview</h3>
    <p>Track the work that matters.</p>
  </div>
  <button type="button" data-cs-ignore>Keep this control static</button>
</section>
<script src="cursor-swarm.js"></script>
<script>
  const swarm = new CursorSwarm({
    root: '#feature-showcase',
    cursors: 3,
    palette: 'ocean',
    deconstruct: false
  }).init();
</script>

Initialize With HTML Attributes

For automatic initialization, load cursor-swarm. js in <head> with data-auto. The script hides the page until the cursors are prepared and exposes the instance as window.cursorSwarm.

<script src="cursor-swarm.js"
        data-auto
        data-cursors="4"
        data-palette="neon"
        data-start-position="corners"
        data-exit-after-build="home"></script>

For manual initialization from <head>, call CursorSwarm.cloak() immediately and initialize on DOMContentLoaded to prevent the original content from flashing:

<script src="cursor-swarm.js"></script>
<script>
  CursorSwarm.cloak();
  document.addEventListener('DOMContentLoaded', () => {
    window.cursorSwarm = new CursorSwarm().init();
  });
</script>

Customize Cursor Colors and Movement

CursorSwarm includes default, neon, pastel, sunset, ocean, forest, candy, mono, and ink palettes. You can register a palette to use your own colors. copyPaste and relocation accept true or a probability from 0 to 1.

CursorSwarm.palettes.cssscript = {
  colors: ['#2a6bf2', '#f25a72', '#16a085']
};
const swarm = new CursorSwarm({
  cursors: 3,
  palette: 'cssscript',
  startPosition: 'outside',
  copyPaste: 0.5,
  relocation: 0.3,
  exitAfterBuild: 'home'
}).init();

Control Build Types in HTML

CursorSwarm assigns a build type to each HTML element. Override it with data-cs. For media, set data-cs-dir to l, r, or t to control the scan direction. data-cs-copy and data-cs-relocate override the corresponding global options.

Build typeAnimation
frameDraws the outline of a box before its background and border appear.
popClicks controls and small items into view.
typeTypes headings and other short text with a caret.
wordsReveals paragraphs and list text word by word.
mediaReveals images and other media with a scanning wipe.
<h2 data-cs="type">A heading built by cursors</h2>
<p data-cs="words" data-cs-label="intro">This paragraph is revealed one word at a time.</p>
<img src="preview.jpg" alt="Product preview" data-cs="media" data-cs-dir="t">
<div data-cs="none"><p>Animate the children, not this container.</p></div>
<div data-cs="skip">Leave this element and its children unchanged.</div>

All Configuration Options

Pass an options object to new CursorSwarm(options) to configure the animation.

Cursors and Scope

OptionDescription
cursors3. Number of cursors when agents is not provided.
agentsnull. Array of agent objects with name, color, role (layout, type, or media), x, and y. A supplied array determines the cursor count.
namesnull. Agent name array or a function of the agent index.
palette'default'. A preset name, 'mono:#ff5e00', a CSS color, an array or comma-separated color list, or { colors, mono, hud }. The optional hud object accepts background, color, mute, and border.
colorsnull. Explicit cursor colors, cycled across agents and taking precedence over palette colors.
startPosition'center'. center, random, corners, top, bottom, left, right, outside, {x,y}, an array of points, or (i,n) => ({x,y}). Coordinates accept pixels or percentage strings.
rootnull (document.body). Element or selector containing the content to animate.
targetsnull. Selector restricting animation to matching elements.
ignorenull. Selector for elements to leave unchanged.

Animation Behavior

OptionDescription
framestrue. Draw frames around eligible boxes.
deconstructtrue. Reverse completed builds when scrolling upward.
exitAfterBuildfalse. true or 'edge' moves idle cursors offscreen; 'home' returns them to their starting points.
idle'dim'. Idle cursor style: dim, stay, or hide.
spawntrue. Animate cursors when they first appear.
speed1. Global speed multiplier.
adaptiveSpeedtrue. Increase speed as the pending work grows.
maxSpeed4. Maximum multiplier applied by adaptive speed.
trigger0.88. Viewport fraction at which an element becomes eligible for building.
typeDuration1.6. Maximum typing duration per text block, in seconds.
copyPastefalse. true uses a 50% chance or specify a probability from 0 to 1.
relocationfalse. true uses a 30% chance or specify a probability from 0 to 1.
respectReducedMotiontrue. Skip the effect when prefers-reduced-motion: reduce is active.

Cursor Overlays and Callbacks

OptionDescription
hudtrue. Show the current task and build progress.
hudPosition'bottom-left'. Also accepts bottom-right, top-left, or top-right.
labelstrue. Show agent names beside cursors.
marqueetrue. Show selection outlines during building.
guidestrue. Show crosshair guides.
sparkstrue. Show completion particles.
carettrue. Show a blinking typing caret.
zIndex2147483000. Stacking level of the cursor overlay.
onBuildnull. (el, type, agentName) callback after an element is built.
onUnbuildnull. (el, type, agentName) callback after an element is deconstructed.
onIdlenull. (agent) callback when an agent becomes idle.
onDonenull. () callback when all registered elements are built.

Public Methods and Properties

MethodDescription
init()Scan content, create the cursors, and start building; returns the instance.
pause()Pause cursor movement and ongoing animation.
resume()Resume a paused swarm.
toggle()Switch between paused and running states.
stop({ reveal: true })Stop and reveal pending elements by default; reveal: false disables the instant reveal.
destroy()Stop, remove the overlay, and restore the original text nodes and affected inline styles.
buildAll()Show all registered content immediately and retain the instance for subsequent work.
refresh()Scan the root for new elements and register them for animation.
add(el, type?)Register an element or selector, optionally specifying a build type.
setSpeed(n)Set the speed multiplier while running.
setPalette(p)Change cursor and HUD colors using a preset or palette value.
on(event, fn)Subscribe to an instance lifecycle event.
off(event, fn)Unsubscribe a previously registered handler.
PropertyDescription
stateCurrent state: idle, running, paused, stopped, or destroyed.
progressFraction of registered items built, from 0 to 1.
colorsArray of current agent colors.
agentsCurrent agent objects.
recordsRegistered element records.

Static API

MemberDescription
CursorSwarm.palettesBuilt-in palette definitions; add a custom preset with a new key.
CursorSwarm.mono(color, count)Generate shades from a base color.
CursorSwarm.inkOn(color)Choose black or white based on the supplied background color.
CursorSwarm.cloak()Hide the page until initialization prepares its animations.

Events

Register listeners before calling init() to capture the initial start event.

EventArguments and timing
startFires after initialization; no arguments.
build(el, type, agentName) when an element is built.
unbuild(el, type, agentName) when an element is deconstructed.
idle(agent) when a cursor becomes idle.
doneFires when all registered elements have been built; no arguments.
pauseFires on pause; no arguments.
resumeFires on resume; no arguments.
stopFires when the swarm stops; no arguments.
destroyFires when the instance is destroyed; no arguments.
palette(palette) when setPalette() updates the palette.
const swarm = new CursorSwarm({ root: '#feature-showcase' });
swarm.on('build', (element, type, agentName) => {
  console.log(agentName, type, element);
});
swarm.on('done', () => {
  console.log('Page build complete');
});
swarm.init();

HTML Attribute Supported

AttributeDescription
data-autoAutomatically initialize when added to the script element.
data-* on the scriptSet supported options in kebab-case. Numeric/boolean strings are parsed, and colors/names accept comma-separated lists. Use JavaScript for object and function values.
data-cs-ignoreExclude this element and its descendants.
data-cs="skip"Exclude this element and its descendants.
data-cs="none"Leave the element itself unchanged, but build eligible children.
data-cs="frame/pop/type/words/media"Force one of the five build types.
data-cs-dirMedia scan direction: l, r, or t.
data-cs-labelCustom text shown for the element in the HUD.
data-cs-copytrue or false to force or prevent copy-paste when eligible.
data-cs-relocatetrue or false to force or prevent relocation when eligible.

Alternatives and Related Resources

You Might Be Interested In:


Leave a Reply