StringTune/Docs

Custom Modules

Module Contract

What StringModule gives you by default: settings, htmlKey matching, attribute mapping, connection flow, and output channels.

Module Contract

StringModule is the authoring base class. It already gives you a connection model, default attribute mapping, object collections, helper methods for mirrored elements, and a full lifecycle surface.

What your module usually sets

Most custom modules define these three things first:

TypeScript
export class StringMyModule extends StringModule {
  constructor(context: StringContext) {
    super(context);
    this.htmlKey = 'my-module';
    this.attributesToMap = [
      ...this.attributesToMap,
      { key: 'my-value', type: 'number', fallback: 0 },
    ];
  }
}
  • htmlKey controls default object matching.
  • attributesToMap declares additional per-object properties to parse.
  • cssProperties is optional and only needed when the module wants CSS.registerProperty(...).

Base attributes you already inherit

StringModule starts with a shared mapping for:

  • active
  • fixed
  • outside-container
  • repeat
  • self-disable
  • abs
  • key
  • offset-top
  • offset-bottom
  • inview-top
  • inview-bottom
  • start
  • end
  • size
  • half-width
  • half-height
  • enter-el
  • enter-vp
  • exit-el
  • exit-vp

That means custom modules automatically get the same geometry-oriented authoring surface as many built-ins.

Attribute mapping

Each entry in attributesToMap has this shape:

TypeScript
{
  key: 'my-value',
  type: 'number',
  fallback: 10,
  transform: (value) => value * 2,
}

How the base class resolves values:

  1. It checks the raw attributes record passed into initializeObject(...).
  2. It looks for key, string-key, and data-string-key.
  3. It falls back to module settings.
  4. It falls back to the mapping fallback value or fallback function.
  5. It parses by type.
  6. It applies transform(...) if present.
  7. It stores the final value on the object with object.setProperty(key, parsed).

Supported parse types

The current base parser supports:

  • number
  • boolean
  • json
  • tuple
  • easing
  • color
  • dimension
  • breakpoint-dimension
  • enum objects like { type: 'enum', values: [...] }

If you need something else, parse it in transform(...) or override initializeObject(...).

Connection and storage

StringModule manages two object collections:

  • objectsOnPage every connected object currently present in the DOM
  • objects objects that are currently entered or active in the module scope

For scroll-oriented modules, objects is usually the hot path collection used on frame or mutate hooks.

Output channels

A custom module normally writes through one or more of these channels:

  • CSS variables
  • inline styles
  • classes
  • helper DOM nodes
  • events

The base class gives you helpers for mirrored output:

  • applyToElementAndConnects(...)
  • applyVarToElement(...)
  • applyPropToElement(...)
  • applyVarToConnects(...)
  • applyPropToConnects(...)

Use these instead of hand-duplicating writes to string-copy-from mirrors.

Custom matching

If htmlKey is not enough, override canConnect(...).

Example:

TypeScript
override canConnect(object: StringObject): boolean {
  return object.keys.includes('progress') && object.keys.includes('rotate-progress');
}

That is the correct place for connection rules. Do not bury connect logic inside onObjectConnected(...).

Cleanup contract

If your module writes persistent styles or subscribes to object-local listeners, clean them up in onObjectDisconnected(...).

That usually means:

  • removing inline styles your module owns
  • removing CSS variables your module owns
  • disconnecting observers created by that module
  • unsubscribing from object.events

Do not remove styles or attributes that belong to other modules.