StringImpulse Module
Design immersive hover responses with cursor-driven micro-interactions. StringImpulse converts pointer velocity into controlled translation and rotation, letting elements lean, lift, or react with tactile realism.
Activation primer: Add
string="impulse"to every element you wantStringImpulseto energise. Supplystring-id="your-id"when you need a stable handle for events, mirrors, orstring-copy-from; otherwise StringTune generates one automatically.
HTML Attributes
| Attribute | Type | Default | Controls | Practical notes |
|---|---|---|---|---|
string-position-strength | number | 3 | Scale of cursor velocity converted to positional force | Raise for snappier lifts; negative values invert direction |
string-position-tension | number | 0.05 | Spring pull-back toward origin | Increase to reduce drift; typical range 0.04–0.12 |
string-position-friction | number | 0.15 | Per-frame damping of velocity | Higher values calm jitter; keep between 0.1–0.3 |
string-position-max-velocity | number | 10 | Clamp for positional speed (px/frame) | Lift for high-energy gestures; lower for subtle motion |
string-position-update-threshold | number | 0.1 | Minimal delta before writing --push-x/--push-y | Raise to reduce CSS churn; drop for micro precision |
string-max-offset | number | 220 | Hard clamp for displacement (px) | Acts as safety net; match component scale |
string-continuous-push | boolean | true | Apply impulses on every move (true) or once per hover (false) | Set to false for single “kick” interactions |
string-rotation-strength | number | 0.75 | Torque multiplier for angular impulse | Negative values invert tilt direction |
string-rotation-tension | number | 0.06 | Restoring torque toward 0deg | Align with position tension for balanced feel |
string-rotation-friction | number | 0.18 | Angular damping per frame | Increase to calm wobble; start 0.15–0.35 |
string-rotation-max-angular-velocity | number | 6 | Clamp for angular speed (deg/frame) | Prevents violent spins; raise carefully |
string-rotation-max-angle | number | 18 | Absolute rotation clamp (deg) | Lower for UI controls, higher for hero visuals |
string-rotation-update-threshold | number | 0.15 | Minimal delta before writing --push-rotation | Lift if transforms flicker on high-refresh panels |
string-sleep-epsilon | number | 0.01 | Threshold to snap back to zero when nearly still | Raise slightly if motion never settles |
Defaults hydrate from
StringTune.setupSettings(). Override globally viastringTune.use(StringImpulse, { ... })or per element with attributes.
Module Snapshot
- Activation attribute:
string="impulse" - CSS variables populated:
--push-x,--push-y,--push-rotation(raw numbers; add units in CSS) - Event hooks:
object:impulse:<id>:move,object:impulse:<id>:rotate,object:impulse:<id>:side - Best suited for: cards, buttons, hero visuals, cursor-followed accents
- Plays well with:
StringCursor, mirror objects (string-copy-from), smooth scroll modes
Basic Usage
- Ensure the engine is already bootstrapped elsewhere in the project. When you are wiring the module in isolation:
import StringTune, { StringImpulse } from '@fiddle-digital/string-tune';
const stringTune = StringTune.getInstance();
stringTune.use(StringImpulse);
stringTune.start(60);
- Annotate responsive elements with
string="impulse"(ordata-string="impulse"). - Consume the variables in CSS—
StringImpulsenever mutates transforms automatically.
<button string="impulse" string-position-strength="2.2" class="cta">Explore</button>
.cta {
transform: translate(calc(var(--push-x, 0) * 1px), calc(var(--push-y, 0) * 1px)) rotate(calc(var(--push-rotation, 0) * 1deg));
transform-origin: 50% 50%;
transition: transform 120ms ease-out;
will-change: transform;
}
How the Module Behaves
- Impulse capture: on each mouse move, cursor velocity plus relative position to the element centre determine fresh impulses. Only elements beneath the pointer receive updates.
- Spring simulation: offsets follow a spring–damper loop, clamped by
position-max-velocityandmax-offset. Rotation mirrors this logic in degrees. - Sleep mode: once displacement and velocity fall below
sleep-epsilon, values snap to zero and CSS writes pause. - Threshold gating: CSS variables update only when deltas exceed the configured thresholds, keeping layout thrash low.
- Latch logic:
continuous-push=falseenables one-shot impulses; the latch resets when the cursor leaves the element.
Event Signals
| Channel pattern | Payload | Fired when | Ideal for |
|---|---|---|---|
object:impulse:<id>:move | { x: number; y: number; } | Rounded --push-x/--push-y values change beyond position-update-threshold | Drive transform stacks, parallax overlays, particle emitters |
object:impulse:<id>:rotate | { rotation: number; } | Smoothed rotation exceeds rotation-update-threshold | Sync shadows, lighting gradients, tilt-driven shaders |
object:impulse:<id>:side | { value: number; } (0=left, 1=right) | Pointer crosses the element while impulse is active | Crossfade hotspots, audio panning, directional cues |
All events share the DOM object's string-id (or generated ID) as <id>. Subscribe via the global event bus you receive from the StringTune instance:
const bus = stringTune; // getInstance already called elsewhere
bus.on('object:impulse:hero-card:move', ({ x, y }) => {
// translate linked WebGL plane, apply easing if needed
});
Tip: when mirroring elements with
string-copy-from, the originating object emits the events; mirrors simply inherit the CSS variables. Use the same<id>to stitch custom logic across layers.
StringImpulse rewards deliberate tuning—lean on the configuration matrix, iterate with the recipes, and lock in values once the interaction supports the product narrative.