magnettype

Per-word axis
variation.

npm ↗
GitHub
TypeScript·Zero dependencies·React + Vanilla JS

CSS applies font-variation-settings to an entire element. Magnet Type applies them word by word — driven by cursor proximity. Words inside the field attract toward a peak axis value; words outside hold at rest. Move your mouse through a paragraph and watch each word respond independently.

Live demo — move your cursor through the text

Mode
Spread Radius80
Weight High900
Weight Low300

Character mode — per-character weight gradient across any block element. Works with mixed content (inline code, links, etc). Move your cursor through the paragraphs below.

Typography has always been a conversation between the reader and the page. Each word on a printed sheet is fixed its weight locked at the moment of setting. But type on screen can breathe, respond, and shift its gravity as the cursor passes through.

Move your cursor slowly across the paragraphs. Characters nearest the cursor rise toward their peak weight, fading back as you move away. The result is a living texture that responds to presence not animation for its own sake, but legibility shaped by attention.

Character mode works per-character across any block element including mixed content with inline code, links, or other elements. The weight gradient follows the cursor continuously, adjusted on scroll so the effect never drifts.

spreadRadius controls how far from the cursor each character's weight fades to its minimum. Use proximityRadius to gate the effect to when the cursor is near the element edge, or omit it to always respond. Both props are independent and combinable.

How it works

The cursor field

Each word gets a span. On every animation frame, the distance from the cursor to each word’s center is measured. Words within the radius receive a font-variation-settings value interpolated between rest and peak — closer words get more of the peak value.

Attract and repel

In attract mode, nearby words approach the peak axis value and far words hold at rest. In repel mode, the logic inverts — words near the cursor stay at rest while words in the outer ring of the field approach peak. Each creates a different reading texture.

Field mode vs legibility mode

Field mode runs a requestAnimationFrame loop driven by cursor position. Legibility mode is static — it wraps visually confusable characters (il1I, rn, 0O) in spans with a boosted wdth axis, improving disambiguation at small sizes without cursor interaction.

Performance via rAF batching

The field loop reads word positions with getBoundingClientRect in a single batch pass, then writes all font-variation-settings in a second pass. No layout thrashing. The loop is cancelled on unmount and restarted when options change.

Usage

TypeScript + React · Vanilla JS

Drop-in component

import { MagnetTypeText } from '@liiift-studio/magnettype'

<MagnetTypeText mode="word" axes={{ wght: [300, 600] }} radius={120}>
  Your paragraph text here...
</MagnetTypeText>

Hook — attach to any element

import { useMagnetType } from '@liiift-studio/magnettype'

const ref = useMagnetType({ mode: 'word', axes: { wght: [300, 600] }, radius: 120 })
<p ref={ref}>{children}</p>

Vanilla JS

import { startMagnetType, getCleanHTML } from '@liiift-studio/magnettype'

const el = document.querySelector('p')
const original = getCleanHTML(el)
const stop = startMagnetType(el, original, { axes: { wght: [300, 600] }, radius: 120 })
// call stop() to cancel the rAF loop and restore markup

Options

OptionDefaultDescription
mode'word''word' — cursor proximity drives per-word font-variation-settings. 'legibility' — static per-character wdth boost for confusable characters.
axes{ wght: [300, 500] }Map of axis tag → [restValue, peakValue]. restValue applies at full distance; peakValue when cursor is directly over the word.
radius120Pixel radius over which the field effect fades. Words beyond this distance receive restValue.
falloff'quadratic''linear' — strength decreases linearly with distance. 'quadratic' — decreases as distance², giving a tighter hot zone.
magnetMode'attract''attract' — words near cursor approach peakValue. 'repel' — words near cursor stay at restValue; far words approach peakValue.
wdthBoost6wdth axis units added to confusable characters in legibility mode. Risk-proportional — highest-risk characters receive the full boost.