StringTune/Docs

Modules

StringCursor

Global cursor runtime that tracks pointer position, writes cursor CSS variables, and manages portal classes.

Type
Built-in module
Status
Stable
Scope
Global
Activation
stringTune.use(StringCursor)

StringCursor

StringCursor is one of the more complex built-in modules. It is global, but it also manages per-object state, floating portal nodes, hover lifecycle cleanup, and multiple output channels.

At a high level it does two separate jobs:

  • writes target-local cursor variables to elements marked with string="cursor"
  • moves optional floating cursor portals marked with string-cursor="..."

That split matters enough that the module now has dedicated deep-dive pages.

Public API

Target Attributes

These attributes are read from elements marked with string="cursor".

| Attribute | Type | Default | Real runtime effect | | -------------------------- | ------------------------------ | ---------------------------- | --------------------------------------------------------------------------------- | ------------------------------------------- | | string-cursor-target | string | default | Selects which cursor portal IDs this target controls. Supports comma or |separated lists.\* targets every portal. | | string-cursor-class | string | "" | Adds this class to matching portals while the target is hovered. | | string-alignment | enum: start, center, end | center | Changes how local --x and --y are normalized. | | string-cursor-enter | enum: snap, smooth | snap | Controls how local cursor values enter when the pointer first touches the target. | | string-cursor-leave | enum: snap, smooth | smooth | Controls how local cursor values reset after leaving the target. | | string-cursor-leave-hold | boolean | false | Freezes the last local values after leaving instead of easing back to zero. | | string-lerp | number | inherited from global lerp | Smoothing factor for target-local cursor motion. | | string-cursor-vars | string list | "" | Enables extra variables: xpx, ypx, dx, dy, angle, angle-deg. |

Portal Attributes

These attributes are read from floating cursor portal elements.

AttributeTypeDefaultReal runtime effect
string-cursorstringdefaultRegisters the portal and gives it an addressable ID.
string-cursor-lerpnumberglobal cursor-lerpChanges how quickly the portal itself follows the pointer.

CSS Variables and DOM Output

The detailed output contract now has its own page:

Target CSS variables

On string="cursor" elements the module writes:

  • --x
  • --y

These are normalized local coordinates, not viewport pixels.

  • alignment="center" gives roughly -1 to 1
  • alignment="start" gives 0 at the left/top edge and 1 at the opposite side
  • alignment="end" gives -1 to 0

If string-cursor-vars includes extra flags, the module also writes:

  • --x-px
  • --y-px
  • --dx
  • --dy
  • --angle
  • --angle-deg

Portal CSS variables

On string-cursor="..." portals the module writes:

  • --x
  • --y
  • --x-lerp
  • --y-lerp

Portal --x and --y are viewport pixel positions, so consume them with * 1px.

Classes

The runtime toggles:

  • -show on portals while at least one linked target is hovered
  • the class from string-cursor-class on matching portals while that target is hovered

Events

StringCursor emits these target-scoped events:

ChannelPayloadFired when
cursor:start:<id>nullTarget-local tracking becomes active
cursor:move:<id>{ x, y }Normalized target-local coordinates change
cursor:pixel:<id>{ x, y }Pixel coordinates inside the target change
cursor:end:<id>nullTarget-local tracking settles or resets

If at least one portal exists, the module also emits a global portal event:

ChannelPayload
cursor{ x, y, stepX, stepY }

Mirror Behavior

If a mirror element is linked with string-copy-from, the target-local CSS variables are written to both the source element and its mirrors. Portal behavior is still owned by the source target ID.

Quick Example

HTML
<div string-cursor="default" class="cursor-portal">
  <span class="cursor-text">View</span>
</div>

<article
  class="project-card"
  string="cursor"
  string-id="project-1"
  string-cursor-target="default"
  string-cursor-class="-view-project"
  string-cursor-enter="smooth"
  string-cursor-leave="smooth"
>
  <img src="/assets/project1.jpg" alt="Project Thumbnail" class="project-image" />
  <div class="project-info">
    <h3>Design System</h3>
    <p>2026</p>
  </div>
</article>
CSS
.cursor-portal {
  position: fixed;
  left: 0;
  top: 0;
  width: 16px;
  height: 16px;
  background: black;
  border-radius: 50%;
  pointer-events: none;
  transform: translate3d(calc(var(--x, 0) * 1px), calc(var(--y, 0) * 1px), 0) translate(-50%, -50%);
  display: flex;
  align-items: center;
  justify-content: center;
}

.cursor-portal:not(.-show) {
  opacity: 0;
}

.cursor-text {
  color: white;
  font-size: 12px;
  opacity: 0;
}

.cursor-portal.-view-project {
  width: 64px;
  height: 64px;
}

.cursor-portal.-view-project .cursor-text {
  opacity: 1;
}

.project-card {
  border: 1px solid black;
  padding: 1rem;
  background: white;
  transform: translate3d(calc(var(--x, 0) * 8px), calc(var(--y, 0) * 8px), 0);
}

Registration

TypeScript
import StringTune, { StringCursor } from '@fiddle-digital/string-tune';

const stringTune = StringTune.getInstance();
stringTune.use(StringCursor, { lerp: 0.8 });
stringTune.start(60);

Detailed Behavior

  • StringCursor does not create a portal for you. If your UI needs a floating cursor, you must add a portal element yourself.
  • string-target-disable and string-target-style-disable are intentionally not documented as supported API. The current runtime parses older setting names, but the current module implementation does not apply those flags.
  • target-class is also intentionally omitted from the supported contract. It is parsed, but not used by the current runtime.
  • On coarse pointer devices the module disables itself.