Overlay and offset signals
Layer temporary or additive motion over a base value without touching the base.
Hover lift, focus nudge, shake — motion that sits on top of a canonical value and must not corrupt it. An overlay signal composes a base and an overlay into a single read, and gives you verbs that animate only the overlay.
overlaySignal
You provide the compose function and a way to project an absolute value back into
overlay space.
const combined = overlaySignal(base, overlay, {
compose: (base, overlay) => base + overlay,
projectAbsoluteToOverlay: (absolute, base) => absolute - base,
});
// Read the composed value
combined();
// Animate only the overlay — the base is untouched
yield* combined.tweenOverlay(20, 0.3);
// Or aim at an absolute value; it is converted to overlay space for you
combined.setAbsolute(100);
yield* combined.tweenTo(100, 0.3);offsetSignal
Numeric shorthand where the overlay is a plain additive offset: base + offset.
const x = offsetSignal(actor.layout.x, signal(0));
yield* x.tweenOverlay(40, 0.2); // 40px from wherever the base currently isInterface
interface OverlaySignal<TValue, TOverlay> {
(): TValue;
peekBase(): TValue;
peekOverlay(): TOverlay;
setOverlay(value: TOverlay): void;
*tweenOverlay(target: TOverlay, options?): Generator;
*transitionOverlay(options, fn): Generator;
setAbsolute(value: TValue): void;
*tweenTo(target: TValue, options?): Generator;
}Use it for
- Hover and focus states layered over canonical position or opacity.
- Camera shake, jitter, or any additive disturbance that should be removable in one write.
- Separating stable authored state from transient visual overlay, so a later authored tween on the base still starts from the value you authored.
Why not just tween the base
Because you would then have to remember to tween it back, and any authored motion that ran in between would start from a polluted value. The overlay keeps "where the thing is" and "how the thing is currently being nudged" as separate facts.