npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@adapt-ux/neuro-ux-sdk-signals

v0.1.0-rc.1

Published

Lightweight behavioral signal detectors that identify focus, overload, motion sensitivity, and interaction patterns for adaptive UI.

Readme

📡 NeuroUX Signals — Signal Manager API Reference

The NeuroUX Signals package provides lightweight behavioral signal detectors that identify user activity patterns (scroll, idle, focus, etc.) for adaptive UI. The Signal Manager is the central module that manages signal lifecycle and connects them to the Core Engine.

This document describes the public API available to developers when using:

import { SignalManager, IdleSignal, ScrollSignal } from "@adapt-ux/neuro-ux-sdk-signals";

Overview

The Signal Manager system consists of three main components:

  1. SignalManager — Manages signal lifecycle and connects to Core Engine
  2. SignalContext — Provides isolated context for each signal to emit values
  3. SignalSnapshot — Maintains current state of all signals for rule evaluation

1. SignalManager

The SignalManager class is responsible for:

  • Instantiating signals from constructors
  • Controlling signal lifecycle (startAll() / stopAll())
  • Receiving values emitted by signals
  • Forwarding values to the Core Engine
  • Maintaining signal snapshot for rule processor

Signature

class SignalManager {
  constructor(
    signalConstructors: Array<new (ctx: SignalContext) => Signal>,
    onEmit: (value: unknown) => void
  );

  startAll(): void;
  stopAll(): void;
  getSnapshot(): Record<string, any>;
  clearSnapshot(): void;
}

Basic Example

import { SignalManager, IdleSignal, ScrollSignal } from "@adapt-ux/neuro-ux-sdk-signals";

// Create manager with signal constructors
const manager = new SignalManager(
  [IdleSignal, ScrollSignal],
  (value) => {
    // This callback receives all signal emissions
    console.log('Signal emitted:', value);
    // Forward to Core Engine for state updates and rule evaluation
  }
);

// Start all signals (only in browser environment)
manager.startAll();

// Get current snapshot for rule evaluation
const snapshot = manager.getSnapshot();
// { idle: { type: 'idle', value: true, ts: 1234567890 }, ... }

// Stop all signals and clean up
manager.stopAll();

Methods

startAll()

Starts all signal instances. Only runs in browser environment (checks for window). Safe to call in SSR environments (no-op).

manager.startAll();

Behavior:

  • Checks if window is defined (SSR safety)
  • Calls start() on each signal instance
  • Handles errors gracefully (logs to console, continues with other signals)

stopAll()

Stops all signal instances and cleans up resources (removes event listeners, clears timers, etc.).

manager.stopAll();

Behavior:

  • Calls stop() on each signal instance
  • Handles errors gracefully
  • Safe to call multiple times

getSnapshot()

Returns the current snapshot of all signal values. Used by Rule Processor for evaluation.

const snapshot = manager.getSnapshot();
// Returns: { idle: { type: 'idle', value: true, ts: 1234567890 }, ... }

Returns: A shallow copy of the current snapshot data.

clearSnapshot()

Clears all snapshot data. Useful for reset scenarios.

manager.clearSnapshot();

2. SignalContext

The SignalContext interface provides the context for signals to emit values. Each signal receives its own isolated SignalContext instance.

Interface

interface SignalContext {
  emit(value: unknown): void;
}

Implementation

The SignalContextImpl class implements this interface:

class SignalContextImpl implements SignalContext {
  constructor(
    snapshot: SignalSnapshot,
    onEmit: (value: unknown) => void
  );

  emit(value: unknown): void;
}

Behavior:

  • Updates the shared snapshot when value has a type property
  • Forwards all emissions to the Core Engine callback
  • Provides isolation between signals

Usage in Custom Signals

When creating custom signals, you receive a SignalContext in the constructor:

import { BaseSignal } from "@adapt-ux/neuro-ux-sdk-signals";
import type { SignalContext } from "@adapt-ux/neuro-ux-sdk-signals";

class CustomSignal extends BaseSignal {
  start() {
    // Emit values through the context
    this.ctx.emit({ type: 'custom', data: 'value' });
  }

  stop() {
    // Cleanup
  }
}

3. SignalSnapshot

The SignalSnapshot class manages the current state of all signals. Each signal update stores its value with a timestamp.

Class

class SignalSnapshot {
  update(value: { type: string; [key: string]: any }): void;
  get(): Record<string, any>;
  clear(): void;
}

Factory Function

function createSignalSnapshot(): SignalSnapshot;

Example

import { createSignalSnapshot } from "@adapt-ux/neuro-ux-sdk-signals";

const snapshot = createSignalSnapshot();

snapshot.update({ type: 'idle', value: true });
snapshot.update({ type: 'scroll', position: 440 });

const data = snapshot.get();
// {
//   idle: { type: 'idle', value: true, ts: 1234567890 },
//   scroll: { type: 'scroll', position: 440, ts: 1234567891 }
// }

Snapshot Structure

Each signal value in the snapshot has the following structure:

{
  [signalType]: {
    type: string;        // Signal type identifier
    ...signalData;       // Additional signal-specific data
    ts: number;          // Timestamp of last update
  }
}

Example:

{
  idle: {
    type: 'idle',
    value: true,
    ts: 1234567890
  },
  scroll: {
    type: 'scroll',
    position: 440,
    ts: 1234567891
  }
}

4. Built-in Signals

IdleSignal

Detects user idle state by emitting periodic updates.

import { IdleSignal } from "@adapt-ux/neuro-ux-sdk-signals";

// Emits every 5 seconds: { type: 'idle', ts: number }

ScrollSignal

Detects scroll position changes.

import { ScrollSignal } from "@adapt-ux/neuro-ux-sdk-signals";

// Emits on scroll: { type: 'scroll', position: number }

5. Creating Custom Signals

To create a custom signal, extend BaseSignal:

import { BaseSignal } from "@adapt-ux/neuro-ux-sdk-signals";
import type { SignalContext } from "@adapt-ux/neuro-ux-sdk-signals";

class FocusSignal extends BaseSignal {
  private handler?: () => void;

  start() {
    this.handler = () => {
      this.ctx.emit({
        type: 'focus',
        active: document.hasFocus(),
      });
    };

    window.addEventListener('focus', this.handler);
    window.addEventListener('blur', this.handler);
    this.handler(); // Initial emission
  }

  stop() {
    if (this.handler) {
      window.removeEventListener('focus', this.handler);
      window.removeEventListener('blur', this.handler);
    }
  }
}

Requirements:

  • Extend BaseSignal
  • Implement start() method
  • Implement stop() method
  • Use this.ctx.emit() to emit values
  • Emit values with a type property for snapshot tracking

6. SSR Safety

The Signal Manager is SSR-safe:

  • startAll() checks for window before starting signals
  • No errors thrown in SSR environments
  • Signals simply don't start in SSR (graceful no-op)
// Safe to call in SSR
manager.startAll(); // No-op if window is undefined

7. Integration with Core Engine

The Signal Manager is designed to integrate with the NeuroUX Core Engine:

import { createNeuroUX } from "@adapt-ux/neuro-ux-sdk-core";
import { SignalManager, IdleSignal, ScrollSignal } from "@adapt-ux/neuro-ux-sdk-signals";

const engine = createNeuroUX({
  profile: "adhd",
  signals: ["idle", "scroll"],
});

// Create signal manager with Core Engine callback
const signalManager = new SignalManager(
  [IdleSignal, ScrollSignal],
  (value) => {
    // Forward to Core Engine for:
    // - Internal state updates
    // - Rule processor evaluation
    // - Future logs
    engine.handleSignal(value);
  }
);

signalManager.startAll();

// Rule processor can access snapshot
const snapshot = signalManager.getSnapshot();
engine.evaluateRules(snapshot);

8. Error Handling

The Signal Manager handles errors gracefully:

  • Errors during startAll() are caught and logged (other signals continue)
  • Errors during stopAll() are caught and logged
  • Invalid signal values are ignored (no snapshot update, but callback still called)

9. Best Practices

  1. Always call stopAll() when cleaning up to prevent memory leaks
  2. Use type property in emitted values for snapshot tracking
  3. Isolate signal logic — each signal should be independent
  4. Handle cleanup in stop() method (remove listeners, clear timers)
  5. Test SSR compatibility — ensure signals don't break in SSR environments

10. Type Definitions

interface SignalContext {
  emit(value: unknown): void;
}

interface Signal {
  start(): void;
  stop(): void;
}

type SignalConstructor = new (ctx: SignalContext) => Signal;

License

MIT