StringTune Event API
StringTune ships with a lightweight event bus shared by every module. Subscribe through the singleton instance, and tap into per-object events via an individual StringObject.
import StringTune from '@fiddle-digital/string-tune';
const stringTune = StringTune.getInstance();
const unsubscribe = (value: number) => {
console.log('Scroll position', value);
};
stringTune.on('scroll', unsubscribe);
// Later
stringTune.off('scroll', unsubscribe);
Need the object itself? Reuse the engine’s registry:
const stringTune = StringTune.getInstance();
const hero = stringTune['objectManager'].all.get('hero');
hero?.events.on('enter', (object) => {
console.log('Hero entered view', object.id);
});
These hooks live on StringObject.events.
| Event | Payload | Description |
|---|
enter | StringObject | Object became active. |
leave | StringObject | Object became inactive. |
Subscribe with object.events.on('enter', handler).
| Event | Payload | Description |
|---|
object:activate:<id> | boolean | Intersection observer toggled the object (true when active). |
object:inview:<id> | { inView: boolean, direction: 'enter-top' | 'enter-bottom' | 'exit-top' | 'exit-bottom' | null } | Fired when scroll crosses the in-view window defined by offsets. |
const stringTune = StringTune.getInstance();
stringTune.on('object:activate:hero', (isActive) => {
console.log('Hero active?', isActive);
});
stringTune.on('object:inview:gallery', ({ inView, direction }) => {
console.log('Gallery in view:', inView, 'direction:', direction);
});
| Event | Payload | Description |
|---|
start | null | Emitted after initialisation completes. |
scroll | number | Current scroll position (pixels). |
lerp | number | Smoothed scroll velocity (same easing used for motion modules). |
update | null | Fired every frame after modules have mutated DOM/CSS. |
scroll:start | null | Wheel/touch input begins. |
scroll:stop | null | Velocity drops below the stop threshold. |
scroll:direction:change | boolean | true when scrolling down, false when scrolling up. |
wheel | WheelEvent | Forwarded wheel events from elements using string="scroller". |
| Event | Payload | Emitted By | Notes |
|---|
object:progress:<id> | number (0–1) | StringProgress | Eased progress applied to DOM and mirrors. |
object:progress-slice:<id> | number (0–1) | StringProgressPart | Remapped sub-range progress for string-part-of. |
object:parallax:<id> | number (pixels) | StringParallax | Current Y translation. |
object:lerp:<id> | number | StringLerp | Scroll velocity applied to the element. |
object:glide:<id> | number (pixels) | StringGlide | Glide displacement; resets to 0 on scroll stop. |
const stringTune = StringTune.getInstance();
stringTune.on('object:progress:hero', (progress) => {
progressBar.style.setProperty('--hero-progress', progress.toFixed(3));
});
stringTune.on('object:parallax:hero', (translation) => {
heroSection.style.transform = `translateY(${translation}px)`;
});
| Event | Payload | Description |
|---|
cursor:start:<id> | null | Pointer begins moving over the element (above epsilon). |
cursor:move:<id> | { x: number, y: number } | Normalized coordinates (respects string-alignment setting). |
cursor:pixel:<id> | { x: number, y: number } | Smoothed pixel offsets relative to element's top-left. |
cursor:end:<id> | null | Pointer stops moving (settles below epsilon). |
cursor | { x: number, y: number, stepX: number, stepY: number } | Global smoothed cursor position in viewport pixels with deltas. |
| Event | Payload | Description |
|---|
magnetic:move:<id> | { x: number, y: number } | Magnetic offset currently applied to item. |
| Event | Payload | Description |
|---|
spotlight:update:<id> | { angleDeg: number, distance: number } | Spotlight direction in degrees and distance. |
| Event | Payload | Description |
|---|
object:impulse:<id>:move | { x: number, y: number } | Current push translation. |
object:impulse:<id>:rotate | { rotation: number } | Rotation in degrees. |
object:impulse:<id>:side | { value: number } | Cursor side factor (0–1) under the pointer. |
const stringTune = StringTune.getInstance();
stringTune.on('cursor:move:cta-button', ({ x, y }) => {
ctaButton.style.setProperty('--cursor-x', x.toString());
ctaButton.style.setProperty('--cursor-y', y.toString());
});
stringTune.on('magnetic:move:cta-button', ({ x, y }) => {
ctaButton.style.transform = `translate(${x}px, ${y}px)`;
});
| Event | Payload | Description |
|---|
form:submit:<id> | Record<string, any> | Serialised form data after successful validation. |
form:invalid:<id> | undefined | Fired when validation fails on submit. |
| Event | Payload | Description |
|---|
image:load:all | null | All managed lazy images finished loading. |
These events replay the last payload for new subscribers.
| Event | Payload | Description |
|---|
screen:mobile | boolean | Mobile media query toggled. |
screen:tablet | boolean | Tablet range toggled. |
screen:laptop | boolean | Laptop range toggled. |
screen:desktop | boolean | Desktop range toggled. |
StringSequence listens for a global sequence event. Emit it when your slider advances.
const stringTune = StringTune.getInstance();
stringTune.emit('sequence', { slider: 'gallery-slider', step: 2 });
| Event | Payload | Description |
|---|
sequence | { slider: string, step: number } | Drives StringSequence state syncing. |
Pair every subscription with stringTune.off(event, handler) when you no longer need it. For per-object hooks, call object.events.off(event, handler) or destroy the object to clear listeners automatically.